mixpplus
11/18/2019 - 7:05 AM

反射


类的初始化时机:
当Java程序首次通过下面6种方式来使用某个类或接口时,系统就会初始化该类或者接口。
1. 创建类的实例(对象)
2. 调用类的类方法
3. 访问类或者接口的类变量,或者为该类变量赋值
4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5. 初始化某个类的子类
6. 直接使用java.exe命令来运行某个主类


类加载器使用ClassLoader表示。Java运行时具有以下内置类加载器:
1. Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null ,并且没有父加载器; 引导类加载器负责加载java的核心类;
2. Platform class loader: 它是平台类加载器; 负责加载JDK中一些特殊的模块;
3. System class loader: 它也被称为应用程序类加载器 ; 它的加载路径是程序运行的当前路径;

这3个类加载器实例之间存在继承关系; 
系统类加载器 --extends--> 平台类加载器 -extends--> 引导类加载器


ClassLoader 中的两个方法
1. static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
2. ClassLoader getParent():返回父类加载器进行委派


反射的定义
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够获取到该类的所有的属性和方法,并且
对其进行使用;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
由于这种动态性,可以极大的增强程序的灵活性,在运行时期可以动态对我们的程序进行扩展;



获取Class对象:
我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型
的对象。一个类只能存在一个Class对象。

这里我们提供三种方式获取Class类型的对象:

1. 使用类的静态class属性来获取该类对应的Class对象。举例:Student.class将会返回
Student类对应的Class对象
Class<Student> studentClazz1 = Student.class;

2. 调用对象的getClass()方法,返回该对象所属类对应的Class对象,该方法是Object类中的
方法,所有的Java对象都可以调用该方法
Student s = new Student();
Class studentClazz2 = s.getClass();

3. 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该
字符串参数的值是某个类的全路径,也就是完整包名的路径  (常用)
Class studentClazz3 = Class.forName("com.itheima.advance.reflect.demo01.Student");

三个Class的对象完全相同,也就是说 一个类只能存在一个Class对象。



反射获取构造方法并创建对象:

Class类中用于获取构造方法的方法:

1、Constructor<?>[] getConstructors():
返回所有公共构造方法对象的数组
2、Constructor<?>[] getDeclaredConstructors():
返回所有构造方法对象的数组
3、Constructor<T> getConstructor(Class<?>... parameterTypes):
返回单个公共构造方法对象
4、Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):
返回单个构造方法对象

Class studentClazz = Class.forName("com.itheima.advance.reflect.demo02.Student");
Constructor clazzConstructor = studentClazz.getConstructor(String.class , int.class);
括号内为该构造器参数类型的类 int的类是int.class String的类是String.class  该方法不带declare所以只能获取公共构造器;

使用该构造器创建对象:
Student s2 = (Student)clazzConstructor.newInstance("张三", 23);

Constructor declaredConstructor = studentClazz.getDeclaredConstructor(String.class)
因为有declare 可以获取私有构造器,私有构造器创建对象时需要设置为强制访问:
declaredConstructor.setAccessible(true);
Student s3 = (Student) declaredConstructor.newInstance("李四");



反射获取成员变量(属性):

1、Field[] getFields(): 返回所有公共成员变量对象的数组
2、Field[] getDeclaredFields(): 返回所有成员变量对象的数组
3、Field getField(String name): 返回单个公共成员变量对象
4、Field getDeclaredField(String name):返回单个成员变量对象

获取Student的字节码文件对象
Class studentClazz = Class.forName("com.itheima.advance.reflect.demo03.Student");

获取name共有属性对象:
Field name = studentClazz.getField("name");

获取age私有属性对象:
Field age = studentClazz.getDeclaredField("age");

调用成员变量对象的方法来给成员变量赋值
void set(Object obj, Object value):给obj对象的该成员变量赋值为value 


	反射中创建对象的三种方式:
	1. 直接new出来
	Student s1 = new Student();

	2. 获取无参构造方法对象,然后通过调用无参构造方法对象去创建一个对象
	Constructor con1 = studentClazz.getDeclaredConstructor();
	Student s1 = (Student) con1.newInstance() ;

	3. 可以使用Class对象中的newInstance方法去创建对象,必须要有公共无参构造器
	Student s1 = (Student)studentClazz.newInstance();

给name公共属性设置值:
name.set(s1 , "张三");

给age私有属性设置值:
age.setAccessible(true);
age.set(s1 , 23);



反射获取成员方法:

1、Method[] getMethods():
返回所有公共成员方法对象的数组,包括继承的

2、Method[] getDeclaredMethods():
返回所有成员方法对象的数组,不包括继承的

3、Method getMethod(String name, Class<?>... parameterTypes) :
返回单个公共成员方法对象

4、Method getDeclaredMethod(String name, Class<?>...parameterTypes): 
返回单个成员方法对象  (常用)

Method info =  clazz.getMethod("info", String.class)
第一个参数 方法名
第二个参数为可变长参数,该方法中所有的参数类型的类对象
返回Method对象

Method中的方法:
public Object invoke(Object obj, Object... args)
第一个参数: 调用该方法的对象
第二个参数: 该方法的所需要的实际参数
返回 执行该方法的返回值

Method info = studentClazz.getDeclaredMethod("info", String.class);
String invoke = (String)info.invoke(changhao, "hello");

如果该方法是静态方法,那么invoke方法中的第一个参数可以使null
String invoke = (String)info.invoke(null, "hello");

如果是私有方法,调用invoke之前需要先调用setAccessble(true);



反射中方法:
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
对象是否有某个反射对象
例如:
boolean flag = IntegerClass.isAnnotationPresent(Override.class)

public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
获取某个注解对象
例如:
Retention annotation = IntegerClass.getAnnotation(Retention.class);
RetentionPolicy value = annotation.value();  //获取注解对象属性的值,返回值为RetentionPolicy枚举对象。