Java学习之路——反射
概述
定义
反射(Reflection)被视为动态语言的关键,通过反射机制可以运行程序在运行期间 获取任何对象的所有信息,并且能够直接操作对象的属性与方法。
Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。
反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。
功能
Java 反射主要提供以下功能:
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
- 在运行时调用任意一个对象的方法和属性;
- 在运行时获取泛型的信息;
- 在运行时处理注解;
- 生成动态代理。
区别
通过反射构造对象与正常方式有着如下区别:
正常情况下:
graph LR A[引入需要的类] --> B[通过 new 实例化] B --> C[获取实例对象]反射机制下:
graph LR A[实例化对象] --> B[调用 getClass 方法] B --> C[得到完整的类] C --> D[构造进的实例对象]
一、Class 类
定义
在 Java 程序种除了八种基本类型外,其他类型全部都是class(包括interface)。而class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。
每加载一种class,JVM就为其创建一个Class(名叫 Class 的 类)类型的实例,并关联起来。
由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此,如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。
这种通过Class实例获取class信息的方法称为反射(Reflection)。
获取 Class 类
方式一:通过类的
class属性获取1Class clazz = String.class;方式二:过该实例变量提供的
getClass()方法获取1 2String s = "Hello"; Class clazz = s.getClass();如果知道一个
class的完整类名,可以通过静态方法Class.forName()获取1Class clazz = Class.forName("java.lang.String");
二、获取字段
Class类提供了以下几个方法来获取字段:
Field getField(name):根据字段名获取某个 public 的 field(包括父类);Field getDeclaredField(name):根据字段名获取当前类的某个 field(不包括父类);Field[] getFields():获取所有 public 的 field(包括父类);Field[] getDeclaredFields():获取当前类的所有 field(不包括父类)。
三、调用方法
Class类提供了以下几个方法来获取Method:
Method getMethod(name, Class...):获取某个public的Method(包括父类);Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类);Method[] getMethods():获取所有public的Method(包括父类);Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)。
四、调用构造器
通过Class实例获取Constructor的方法如下:
getConstructor(Class...):获取某个public的Constructor;getDeclaredConstructor(Class...):获取某个Constructor;getConstructors():获取所有public的Constructor;getDeclaredConstructors():获取所有Constructor。
五、获取继承关系
通过Class对象可以获取继承关系:
Class getSuperclass():获取父类类型;Class[] getInterfaces():获取当前类实现的所有接口。
六、使用反射
| |
七、动态代理
我们知道,在 Java 程序中所有interface类型的变量总是通过向上转型并指向某个实例的。
那么有没有可能不编写实现类,直接在运行期创建某个interface的实例呢?
这是可能的,因为Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以在运行期动态创建某个interface的实例。
在运行期动态创建一个interface实例的方法如下:
- 定义一个
InvocationHandler实例,它负责实现接口的方法调用; - 通过
Proxy.newProxyInstance()创建interface实例,它需要3个参数:- 使用的
ClassLoader,通常就是接口类的ClassLoader; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler实例。
- 使用的
- 将返回的
Object强制转型为接口。
| |