首页 > 其他分享 >反射

反射

时间:2023-05-26 20:14:07浏览次数:42  
标签:反射 System clazz Person 时类 Class out

反射的概述(Java Reflection)

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像以面镜子,透过镜子看到类的结构,所以我们形象的称之为:反射。
正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象
反射方式:实例化对象->getClass()方法->得到完整的“包类”名称

动态语言vs静态语言
1.动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。
主要动态语言:Object-c、C#、JavaScript、PHP、Python、Erlang

2.静态语言
与动态语言相对应,运行时结构不可变的语言就是静态语言如java、c、c++

Java不是动态语言,但Java可以称之为“准动态语言”,即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的适合更加灵活!

反射机制的研究及应用
Java反射机制提供的功能:

在运行时判断任意一个对象所属的类
在运行是构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型的信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理

反射相关的主要API

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器

//实例:反射之后,对于Person的操作
@Test
public void test2() throws Exception{
	Class clazz = Person.class;
	//1.通过反射,创建Person类的对象
	Constructor cons =  clazz.getConstructor(String.class,int.class);
	Object obj = cons.newInstance("Tom",12);
	Person p = (Pserson)obj;
	System.out.println(obj.toString());
	//2.通过反射,调用对象指定的属性、方法
	//调用属性
	Field age = clazz.getDeclaredField("age");
	age.set(p,10);
	System.out.println(p.toString());
	//调用方法
	Method show = clazz.getDeclaredMethod("show");
	show.invoke(p);
	
	//通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
	Constructor cons1 =  clazz.getDeclaredConstructor(String.class);
	cons1.setAccessiable(true);
	Person p1 = (Person)cons1.newInstance("Jerry");
	System.out.println(p1);
	
	Field name =  clazz.getDeclaredField("name");
	name.setAccessiable(true);
	name.set(p1,"Hanmeimei");
	//调用私有方法
	Method showNation = clazz.getDeclaredMethod("showNation",String.class);
	showNation.setAccessible(true);
	String nation = (String)showNation.invoke(p1,"中国");//相当于P1.showNation("中国")
	System.out.println(nation);
}

反射机制与面向对象中的封装性是否是矛盾的,如何看待两个技术。
不矛盾。反射的特性:动态性。反射表现为是否去掉,封装性表现为是否可掉

关于Java.lang.Class的理解:
1.类加载过程:
程序经过javac.exe命令以后,会生成一个活多个字节码文件(.class)结尾,接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载内存中的类,就称为运行时类,此运行时类,就作为Class的一个实例

2.换句话说,Class的实例就对应着一个运行时类。
3.加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。

//如何获取Class实例的方式:(前三种方式需要掌握)
//方式一:调用运行时类的属性:.class
Class<Person> clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("com.java.Person");
System.out.println(clazz3);
System.out.println(clazz1==clazz2);//true
System.out.println(clazz1==clazz3);//true

//方式四:使用类的加载器:Classloader
ClassLoader classloader =  当前类.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.java.Person");
System.out.println(clazz4);
System.out.println(clazz1==clazz4);

类加载器的作用:
类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在队中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。

Properties pros = new Properties();
//读取配置文件方式一:当前module下。
//FileInputStream fis  = new FileInputStream("jdbc.properties");
//pros.load(fis);
//读取配置方式二:使用ClassLoader 当前module的src下
ClassLoader classLoader= 当前类.class.getClassLoder();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
String user = pros.getProperty("user");
System.out.println("user="+user);

创建运行时类的对象

@Test
public void test1(){
	Class clazz = Person.classs;
	//newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参构造器
	//要想此方法正常的创建运行时类的对象  要求:
	//1.运行时类必须提供空参的构造器
	//2.空参的构造器的访问权限得狗。通常为public
	
	//在javabean中要求提供一个public的空参构造器。原因:
	//1.便于通过反射,创建运行时类的对象
	//2.便于子类继承此运行时类时,默认调用super()时,保证此类有此构造器
	Pserson obj = (Pserson)clazz.newInstance();
	System.out.print(obj);
}
@Test
public void test2(){
	int num = new Random().nextInt(3);//0,1,2
	switch(num){
		case 0:
			classPath="java.util.Date";
			break;
		case 1:
			classPath="java.lang.Object"
			break;
		class 2:
			classPath="com.java.Person";
			break;
	}
	Object obj = getInstance(classPath);
}
//创建一个指定类的对象
//classPath:指定类的全类名
public Object getInstance(String classPath)throws Exception(){
	Class clazz = Class.froName(classPath);
	return clazz.newInstance();
}

获取当前运行时类的属性结构

	@Test
	public void test1(){
		Class clazz = Person.class();
		//获取属性结构
		//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
		Field[] fields = clazz.getFields();
		for(Filed f : fields){
			System.out.println(f);
		}
		//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
		Field[] declaredFields = clazz.getDeclaredFields();
		for(Field f :declaredFields){
			System.out.println(f);
		}
	}
	
	
	//权限修饰符 数据类型 变量名
	@Test void test2(){
		Class clazz = Person.class;
		Field[] declaredFields=clazz.getDeclaredFields();
		for(Field f : declaredFields){
			//1.权限修饰符
			int modifier = f.getModifiers();
			//将权限修饰符站视出来
			System.out.print(Modifier.toString(modifier)+"\t");
			
			//2.数据类型
			Class type = f.getType();
			System.out.print(type.getName()+"\t");
			
			//3.变量名
			String fName=f.getName();
			System.out.print(fName);
		}
	}

获取运行时类的方法结构

Class clazz  = Person.class();
//getMethods():获取当前运行时类及其所有父类中生米给你为public 权限的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
	System.out.println(m);
}
//getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
	System.out.println(m);
}
//@Xxx
//权限修饰符 返回值类型 方法名(参数类型1 形参名1,...)throws XxxException{}
	//1.获取方法声明的注解
	Class clazz = Person.class;
	Method[] declaredMethods = clazz.getDeclaredMethods();
	for(Method m : declaredMethods){
		//1.获取方法声明的注解
		Annotation[] annos = m.getAnnotations();
		for(Annotation a: annos){
			System.out.println(a);
		}
		//2.权限修饰符
		System.out.print(Modifier.toString(m.getModifiers())+"\t");
		//3.返回值类型
		System.out.print(m.getReturnType().getName()+"\t");
		//4.方法名
		System.out.print(m.getName());
		System.out.print("(");
		//5.形参列表
		Class[] parameterTypes = m.getParamterTypes();
		if(!(parameterTypes==null && parameterTypes.length==0)){
			for(int i=0;i<paramterTypes.length;i++){
				if(i==parameterTypes.length-1){
					System.out.print(parameterTypes[i].getName()+" args_"+i);
					break;
				}else{
					System.out.print(parameterTypes[i].getName()+" args_"+i+",");
				}
				
			}
		}
		System.out.print(")");
		//6.抛出的异常
		Class[] exceptionTypes =  m.getExceptionTypes();
		if(exceptionTypes.length>0){
			System.out.print("throws ");
			for(int i=0;i<exceptionTypes.lengvth;i++){
				if(i==exceptionTypes.length-1){
					System.out.println(exceptionTypes[i].getName());
					break();
				}else{
					System.out.println(exceptionTypes[i].getName()+",");
				}
				
			}
		}
		System.out.println();
	}

获取其他

//获取构造器
@Test
public void test1(){
	Class clazz  = Person.class();
	//getConstructors():获取当前运行时类中声明为public的构造器
	Constructor[] constructors =  clazz.getConstuctors();
	for(Constructor c : constructors){
		System.out.println(c);
	}
	System.out.println();
	//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
	Constructor[] declaredConstructors =  clazz.getDeclaredConstructors();
	for(Constructor c: declaredConstructors){
		System.out.println(c);
	}
	
	//获取运行时父类
	Class superclass= clazz.getSuperclass();
	System.out.println(superclass);
	
	//获取运行时类带泛型的父类的泛型
	Type genericSuperclass = clazz.getGenericSuperclass();
	ParameterizedType paramType = (ParameterizedType)genericSuperclass;
	//获取泛型类型
	Type[] actulaTypeArguments =  paramType.getActualTypeArguments();
	System.out.println(genericSuperclass[0].getTypeName());
	
	//获取运行时类实现的接口
	Class[] interfaces =  clazz.getInterfaces();
	for(Class c : interfaces){
		System.out.println(c);
	}
	System.out.println();
	//获取运行时父类实现的接口
	Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
	for(Class c: interfaces){
		System.out.println(c);
	}
	//获取运行时类所在的包
	Package pack = clazz.getPackage();
	System.out.println(pack);
	//或许运行时类所声明的注解
	Annotation[] annotations = clazz.getAnnotations();
	for(Annotation annos:annotations){
		System.out.println(annos);
	}
}

调用运行时类的指定结构:属性、方法、构造器

@Test
public void testField()throws Exception{
	Class clazz = Person.class;
	
	
	//创建运行时类的对象
	Person p = (Person) clazz.newInstance();
	
	//获取指定属性:要求运行时中类中的属性声明为public
	//通常不用此方法
	Field id = clazz.getField("id");
	
	//设置当前属性的值
	//ser():参数1:指明设置那个对象的属性 参数2:将此属性值设置为多少
	id.set(p,1001);
	//获取当前属性的值
	//get():参数1:Huoqu那个对线的当前属性值
	int pId=(int)id.get(p);
}
@Test
public void testField1() throws Exception{
	Class clazz = Person.class;
	//创建运行时类的对线
	Person p = (Person)clazz.newInstance();
	
	//getDeclaredField(Streingf filedName):获取运行时类中指定变量名的属性
	Filed name =  clazz.getDeclaredField("name");
	//2.保证当前属性是可以访问的
	name.setAccessiable(true);
	name.set(p,"Tom");
	System.out.println(name.get(p));
}
@Test
public void testMethod() throws Exception{
	//如何获取运行中指定的方法 --需要掌握
	Class clazz = Person.class;
	//创建运行时类的对象
	Person p = (Person)clazz.newInstance();
	//1.获取指定的某个方法,getDeclaredMethod():参数1:指明获取的方法的名称 参数2:指明获取的方法的形参列表
	Method show = clazz.getDeclaredMethod("show",String.class);
	show.setAccessiable(true);
	//invoke():参数1:方法的调用者,参数2:给方法形参赋值的实参,invoke()的返回值几位对应类中调用的方法的返回值
	Object returnValue  =show.invoke(p,"CHN");
	System.out.println(returnValue);
	
	
	//如何调用静态方法
	Method showDesc = clazz.getDeclaredMethod("showDesc");
	showDesc.setAccessible(true);
	//如果调用的运行时类中没有返回值,此时invoke()返回null
	Object returnVal = showDesc.invoke(Person.class);
	//Object returnVal = showDesc.invoke(null);
	System.out.println(retrurn Val);//null
}
//如何调用运行时类中的指定的构造器
@Test
public void testConstructor()throws Exception{
	Class clazz = Person.class;
	//1.获取指定的构造器
	//getDeclaredConstructor():参数:指明构造器的参数列表
	Constructor constructor = clazz.getDeclaredConstructor(String.class);
	//2.保证此构造器是可访问的
	constructor.setAccessible(true);
	//3.调用此构造器创建运行时类的对象
	Person per = (Person)constructor.newInstance("Tom");
	System.out.println(per);

}

标签:反射,System,clazz,Person,时类,Class,out
From: https://www.cnblogs.com/rhy2103/p/17433254.html

相关文章

  • PHP 反射机制打印对象
    1<?php2/**34echoObj::new('Redis');5echoObj::new('Redis')->method('set')?->isPublic();67*/89classObjextendsReflectionClass10{11publicstaticfunctionstd(?array$attrs=null)1......
  • C# 反射的定义和应用场景
     1什么是反射首先要复习一下C#的编译过程,可以解释为下图其中dll/exe中,包括元数据(metadata)和IL(中间语言IntermediateLanguage)另外还出现的其他名词:CLR(公共语言运行时,CommonLanguageRuntime)和JIT(实时编译器JustinTime)总结:一个运行的程序查看本身的元数据或......
  • 【Java基础】万字长文深入理解Java反射机制
    大家好,我是程序员青戈,一个被Bug耽误了才艺的程序员......
  • java反射代码案例
    反射案例代码点击查看代码packagecom.bh.zoo;publicclassWolfextendsAnimal{publicStringname;publicStringcolor;protectedStringblood;privateintage;publicvoideat(){System.out.println("狼吃肉");}public......
  • java 反射:类和属性是否有注解
    booleanisAnnotationPresent(Class<?extendsAnnotation>annotationClass)元素上是否包含指定类型的注解,存在则返回true,否则返回false<AextendsAnnotation>AgetAnnotation(Class<A>annotationClass)获取元素上指定的注解,如果元素没有该注解返回null<AextendsAnn......
  • 2023.5.21学习内容 多态、接口、泛型、反射
    下午1.了解CSS响应式布局和兼容性问题2.浏览IDEA使用手册并修改Maven仓库设置3.复习强化JavaSE的多态、接口、泛型、反射知识importorg.junit.Test;importtest.Hello;importjava.lang.reflect.Field;importjava.util.ArrayList;importjava.util.LinkedList;import......
  • 反射机制
    1. 问题引入1. 根据配置文件re.properties指定信息,创建Cat对象并调用方法hiclassfullpath = com.stulzl.cat.Catmethod= hi使用现有的技术能不能做到?2.这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码情况下,来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源......
  • 类加载和通过反射获取类的结构信息
    1. 基本说明  719反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。1.静态加载:编译时加载相关的类,如果没有写出该类,则报错,依赖性太强2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错,降低了依赖性代码在com.stulzl.class_load_.包中Clas......
  • Reflection反射在iOS下使用Objective-C 具体如何使用
       反射,一种计算机处理方式。是程序可以访问、检测和修改它本身状态或行为的一种能力。程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调......
  • Java 世界的法外狂徒:反射
    概述反射(Reflection)机制是指在运行时动态地获取类的信息以及操作类的成员(字段、方法、构造函数等)的能力。通过反射,我们可以在编译时期未知具体类型的情况下,通过运行时的动态查找和调用。虽然Java是静态的编译型语言,但是反射特性的加入,提供一种直接操作对象外的另一种方式,让......