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
属性获取1
Class clazz = String.class;
方式二:过该实例变量提供的
getClass()
方法获取1 2
String s = "Hello"; Class clazz = s.getClass();
如果知道一个
class
的完整类名,可以通过静态方法Class.forName()
获取1
Class 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
强制转型为接口。
|
|