java反射
Contents
反射机制是java语言提供动态特性的机制。动态特性,指一段代码, 改变其中的变量,即可对这段代码产生功能性的变化[1]。
基本语法
设想有一个Person类
|
|
当我们想使用此类时,需要实例化它,并使用它的属性
|
|
这是我们正常使用类时的方法, 除了这种方法,有时候我们不想 import
此类就想使用其方法,反射就可以派上用场了。
同样是上面的setName、getName功能, 用反射实现的代码为:
|
|
可以看到,只需要一个包名:reflect.Person 即可使用Person的public函数了
反射用到的方法如下:
- 获取类的⽅法: forName
- 实例化类对象的⽅法: newInstance
- 获取函数的⽅法: getMethod
- 执⾏函数的⽅法: invoke
newInstance 方法的一些问题
当我们使用反射的newInstance方法时,可能会出现一些问题。
此方法的文档如下:
Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized.
当我们使用newInstance,实际上是调用该类的无参构造函数, 例如在上面的例子里Object personInstance = cls.newInstance();
就
调用了Person类的Person()方法。
但是要注意, 以下情况会导致newInstance调用失败:
- 该类没有无参构造函数(注意:当我们没写构造函数时默认存在一个无参构造函数)
- 该类的构造函数是私有的
以下针对上面两种情况分析.
该类没有无参构造函数
这种情况可以使用getConstructor函数传入构造函数参数
Params: parameterTypes – the parameter array
Returns: the Constructor object of the public constructor that matches the specified parameterTypes
假如上面例子的构造函数为:
|
|
我们可以这样传入参数反射:
|
|
如果参数类型是List
|
|
可以传入list类型的参数
|
|
总之传入对应的参数类型和参数即可。
值得一提的是, 对于可变参数, 如Person(String...names)
, 它和Person(String[] names)
是等价的
因此我们可以这样写:
|
|
该类的构造函数是私有的
一般这种类用于单例模式。
改下上面的例子的构造函数为private, 为避免复杂化, 先不要参数:
|
|
这时候需要用到反射的getDeclaredConstructor函数了,先看最终代码:
|
|
这里可以先介绍以下getDeclaredMethod函数,它和getMethod函数的区别在于:
- getDeclaredMethod 方法获取的是当前类中“声明”的方法,包括私有的方法,但不包含从父类里继承来的方法
- getMethod 方法获取的是当前类中所有公共方法,包括从父类继承的方法
getDeclaredMethod获取到的method可以设置可访问性: 即 setAccessible, 设置为true之后就可以访问私有的方法了。
至于上面私有的构造方法,也是同理。