JAVA反射笔记

一、反射相关的主要API

java.lang.Class:代表一个类 用来描述类的类 (每个类都有构造器、变量、方法等相似点,因此抽象描述为一个Class类)
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器

二、java.lang.Class

1.关于java.lang.Class类的理解:

1) 类的加载过程:程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
      接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。
      加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。换句话说,Class的实例就对应着一个运行时类。(万事万物皆对象)
2)加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。

2.获取类的方式:(获取Class类的实例)

主要有以下四种,其中第三种最常用:

public void test01() {        
	//方式一:调用运行时类的属性:.class        
	Class clazz1 = Person.class;
        //方式二:通过运行时类的对象,调用getClass()        
        Person p1 = new Person();        
        Class clazz2 = p1.getClass();
        //方式三:调用Class的静态方法:forName(String classPath)       
        Class clazz3 = Class.forName("com.xxx.java.Person");
        //方式四:使用类的加载器:ClassLoader  (了解)        
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.xxx.java.Person");
	//以下输出都是true        
	System.out.println(clazz1 == clazz2);        
	System.out.println(clazz1 == clazz3);        
	System.out.println(clazz1 == clazz4);
}
3.class实例可以是哪些结构:
public void test02(){        
	Class c1 = Object.class;       
	Class c2 = Comparable.class;        
	Class c3 = String[].class;        
	Class c4 = int[][].class;        
	Class c5 = ElementType.class;	//枚举类        
	Class c6 = Override.class;		//注解        
	Class c7 = int.class;			//基本数据类型        
	Class c8 = void.class;		//void        
	Class c9 = Class.class;		//Class本身
	
	int[] a = new int[10];        
	int[] b = new int[100];        
	Class c10 = a.getClass();       
 	Class c11 = b.getClass();        
 	// 只要数组的元素类型与维度一样,就是同一个Class,输出true        	
 	System.out.println(c10 == c11);    
 }
4.类的加载与ClassLoader

1)类加载过程中的“加载”阶段会将类的class文件读入内存,并为之创建一个Class对象,此过程由类的加载器完成。该Class指的就是java.lang.Class
2)类加载器的作用:
      a.类加载:将class文件字节码内容加载到内存中, 并将这些静态数据转换成方法区的运行时数据结构, 然后在堆中生成一个代表这个类的java.lang.Class对象, 作为方法区中类数据的访问入口。
      b.类缓存:标准的JavaSE类加载器可以按要求查找类, 但一旦某个类被加载到类加载器中, 它将维持加载(缓存) 一段时间。 不过JVM垃圾回收机制可以回收这些Class对象。(这也就是上面的test01()为什么输出为true)

三、创建运行时类的对象

      newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。
要想此方法正常的创建运行时类的对象,要求:
      1.运行时类必须提供空参的构造器
      2.空参的构造器的访问权限得够。通常,设置为public。
在javabean中要求提供一个public的空参构造器。原因:
      1.便于通过反射,创建运行时类的对象(很多框架底层就是使用反射创建对象)
      2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器

public void test03() throws IllegalAccessException, InstantiationException {        
	Class<Person> clazz = Person.class;        
	Person obj = clazz.newInstance();
}

四、获取运行时类的完整结构

public void test04(){        
	Class clazz = Person.class;        
	//getFields():获取当前运行时类及其父类中声明为public访问权限的属性,包括:权限修饰符,数据类型,变量名        
	Field[] fields = clazz.getFields();        
	//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)        
	Field[] declaredFields = clazz.getDeclaredFields();        

	//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法,
	//包括:注解,权限修饰符,返回值类型,方法名(参数类型1 形参名1,...) throws XxxException{}        
	Method[] methods = clazz.getMethods();        
	//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)        
	Method[] declaredMethods = clazz.getDeclaredMethods();

	//getConstructors():获取当前运行时类中声明为public的构造器        
	Constructor[] constructors = clazz.getConstructors();        
	//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器        
	Constructor[] declaredConstructors = clazz.getDeclaredConstructors();        

	//获取运行时的父类 
	Class superclass = clazz.getSuperclass();
	//获取运行时类的带泛型的父类
	Type genericSuperclass = clazz.getGenericSuperclass();
	//获取运行时类的带泛型的父类的泛型        
	ParameterizedType paramType = (ParameterizedType) genericSuperclass;        
	//获取泛型类型        
	Type[] actualTypeArguments = paramType.getActualTypeArguments(); 
	System.out.println(actualTypeArguments[0].getTypeName());

	//获取运行时类实现的接口
	Class[] interfaces = clazz.getInterfaces();
	//获取运行时类的父类实现的接口
	Class[] interfaces1 = clazz.getSuperclass().getInterfaces();

	//获取运行时类所在的包
	Package pack = clazz.getPackage();
	
	//获取运行时类声明的注解
	Annotation[] annotations = clazz.getAnnotations();    }

五、调用运行时类的指定结构

public void test05() throws Exception {        
	Class clazz = Person.class;        
	//创建运行时类的对象        
	Person p = (Person) clazz.newInstance();
	
//获取指定的属性
	//下面的方法不常用,因为只能获取运行时类中声明为public的属性        
	Field id = clazz.getField("id");        
	//下面的方法更常用:
	//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性        
	Field name = clazz.getDeclaredField("name");        
	//2.保证当前属性是可访问的        
	name.setAccessible(true);        
	//3.获取、设置指定对象的此属性值。        
	name.set(p,"Tom"); name.get(p);

//获取运行时类中的指定的方法
	//1.获取指定的某个方法 
	//getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表 Method method1= 
	clazz.getDeclaredMethod("methodName", String.class); 
	//2.保证当前方法是可访问的 
	method1.setAccessible(true);
	//3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参
	//invoke()的返回值即为对应类中调用的方法的返回值(和原来方法的返回值一样)。如果调用的运行时类中的方法没有返回值,则此invoke()返回null
	Object returnValue = show.invoke(p,"str1"); 

//如何调用静态方法 
	Method staticMethod1 = clazz.getDeclaredMethod("methodName2"); staticMethod1.setAccessible(true);
	//invoke()方法参数1:可以传入类,也可以传入null  参数2:给方法形参赋值的实参
	Object returnVal = staticMethod1.invoke(Person.class);

//获取指定的构造器,通常不使用该方法创建对象,而是直接使用newInstance()方法调用无参构造器,具体见第三点        
	//getDeclaredConstructor():参数:指明构造器的参数列表        
	Constructor constructor = clazz.getDeclaredConstructor(String.class);        
	//2.保证此构造器是可访问的        
	constructor.setAccessible(true);        
	//3.调用此构造器创建运行时类的对象        
	Person per = (Person) constructor.newInstance("Tom"); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值