1、反射概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有(包括私有)属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取类的信息以及动态调用对象的方法的功能称为java的反射机制。
反射就是把java类中的各种成分映射成一个个的Java对象。
2、Class对象(在运行期间,一个类产生一个Class对象)
Class对象是将class文件读入内存,并为之创建一个Class对象(字节码对象)。
获取Class对象的三种方式:
1).通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。
Object ——> 对象.getClass()
2).每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。
类名.class
3).使用Class类中的静态方法forName方法。
Class.forName(全限定类名)
基本类型对应的包装类型都有TYPE属性,可以得到这个基本类型的CLASS类型
注意:TYPE实际上获取的是封装类对应的基本类型的Class对象的引用,所以可以判断出int.class == Integer.TYPE 返回true,int.class==Integer.class返回false。
通过这种方式不会初始化静态域。使用类名.TYPE的方式获取Class对象叫做类的字面常量。这样做不仅更简单,而且更安全,因为它在编译时就会受到检查(因此不需要置于try语句块中),并且它根除了对forName方法的引用,所以也更高效。
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Float.TYPE;
Class c4 = Double.TYPE;
3、构造方法
1).批量方法:
方法 | 解释 |
---|---|
Class–> public Constructor[] getConstructors() | 所有"公有的"构造方法 |
Class–>public Constructor[] getDeclaredConstructors() | 获取所有的构造方法(包括私有、受保护、默认、公有) |
2).单个方法:
方法 | 解释 |
---|---|
Class–>public Constructor getConstructor(Class… parameterTypes) | 获取单个的"公有的"构造方法 (空参可设置为null) |
Class–>public Constructor getDeclaredConstructor(Class… parameterTypes) | 获取"某个构造方法"可以是私有的,或受保护、默认、公有 |
3).实例化:
newInstance是 Constructor类的方法(管理构造函数的类)
默认调用构造函数 :Class对象.newInstance()
Constructor对象.newInstance(Object… args),若是空参构造函数,args为空或者null
4、成员变量
1).批量方法:
方法 | 解释 |
---|---|
Class–>Field[] getFields() | 返回Field 对象数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。如果该 Class 对象表示一个类,则此方法返回该类及其所有超类的公共字段。如果该 Class 对象表示一个接口,则此方法返回该接口及其所有超接口的公共字段 |
Class–>Field[] getDeclaredFields() | 返回 Field 对象数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段 |
2).单个方法:
方法 | 解释 |
---|---|
Class–>public Field getField(String fieldName) | 获取某个"公有的"字段 |
Class–>public Field getDeclaredField(String fieldName) | 获取某个字段(私有、受保护、默认、公有) |
3).字段信息
设置字段值
方法 | 解释 |
---|---|
Field -->public void set(Object obj,Object value) | 1.obj:要设置的字段所在的对象;2.value:要为字段设置的值 |
若属性为不可见的,则需要暴力反射,解除私有限定
方法 | 解释 |
---|---|
Field --> setAccessible(true) | 暴力反射,解除私有限定 |
获取字段值
方法 | 解释 |
---|---|
Field -->public Object get(Object obj) | obj:要获取的字段所在的对象 |
5、成员方法
1).批量方法:
方法 | 解释 |
---|---|
Class–> public Method[] getMethods() | 返回 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共成员方法(包含了父类的方法也包含Object类) |
Class–>public Method[] getDeclaredMethods() | 返回 Method 对象数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法 |
2).单个方法:
方法 | 解释 |
---|---|
Class–>public Method getMethod(String name,Class<?>… parameterTypes) | name : 方法名;Class : 形参的Class类型对象 |
Class–>public Method getDeclaredMethod(String name,Class<?>… parameterTypes) | name : 方法名;Class : 形参的Class类型对象 |
3).调用方法
方法 | 解释 |
---|---|
Method --> public Object invoke(Object obj,Object… args) | obj : 要调用方法的对象(若方法为静态方法,则设置为null);args:调用方法时所传递的实参 |
Method --> setAccessible(true) | 暴力反射,解除私有限定 |
6、反射应用
1).通过反射运行配置文件内容
利用反射和配置文件可以使应用程序更新时,对源码无需进行任何修改,只需要将新类发送给客户端,并修改配置文件即可
2).通过反射越过泛型检查
泛型用在编译期,编译过后泛型擦除(消失掉),而反射是在应用程序运行阶段,所以可以通过反射越过泛型检查的
3).动态代理
利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象)
a new出代理对象,通过实现InvocationHandler接口,然后new出代理对象来。
b 通过Proxy类中的静态方法newProxyInstance,来将代理对象假装成那个被代理的对象,也就是如果叫人帮我们代买火车票一样,那个代理就假装成我们自己本人。
c 执行方法,代理成功
public class MyInvocationHander implements InvocationHandler {
//目标对象
private Object target;
public MyInvocationHander(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.err.println("开始");
method.invoke(target, args); //执行被代理的target对象的方法
System.out.println("结束");
return null;
}
}
Student student = new StuImp();
MyInvocationHander m = new MyInvocationHander(student);
/**
* student.getClass().getClassLoader():类加载器
* student(实际对象是StuImp类型)
* student.getClass().getInterfaces():被代理对象实现的接口
* m:代理对象
*/
Student s = (Student) Proxy.newProxyInstance(student.getClass().getClassLoader(),
student.getClass().getInterfaces(), m);
s.login();
s.logout();
4).在运行时判断任意一个对象所属的类
// public boolean isInstance(Object obj)
// 当该 Class 对象表示一个已声明的类时,若指定的 Object 参数是所表示类(或其任一子类)的一个实例,则此方法返回 true;否则返回 false
Class aClass = Class.forName("com.Dan.Consumer");
System.out.print(aClass.isInstance(new Consumer()));