反射
概念
- 反射机制:动态获取类的信息以及动态调用对象的方法的功能
Java反射机制:是指在程序运行状态中
任意一个类,通过反射都能获取到该类的所有属性和方法
任意一个对象,通过反射都能够调用它的任意一个方法和属性
常见的应用场景
- IDEA编辑器
将对象的方法和属性展示出来就使用利用了反射机制,该对象所有类进行了解剖获取到了类中的所有方法和属性信息
- 框架
所有的框架都是在反射的基础上实现的,如果没有反射我们常用的框架将大概率不复存在,例如:Spring中IOC容器的实例化就是基于工厂模式+反射实现的。
- 运用前提
要想解剖一个类,必须先要获取到该类的.class文件对象。而解剖使用的就是Class类中的方法.所以要先获取到每一个字节码文件对应的Class类型的对象。
Class类:描述类信息的类,其中包含了与类有关的信息,比如属性、方法等
获取给定类Class对象的方式
通过[类名].class
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<RockMan> clazz = RockMan.class;
System.out.println("RockMan clazz by .class = " + clazz);
// 创建该类的实例
RockMan rockMan = clazz.newInstance();
System.out.println("rockMan = " + rockMan);
}
通过[对象].getClass方法
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
RockMan rockMan = new RockMan();
Class<? extends RockMan> clazz = rockMan.getClass();
System.out.println("RockMan clazz by getClass = " + clazz);
RockMan rockMan = clazz.newInstance();
System.out.println("rockMan = " + rockMan);
}
通过Class.forName()方法
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<?> clazz = Class.forName("com.rock.base.RockMan");
System.out.println("RockMan clazz by Class.forName = " + clazz);
RockMan rockMan = clazz.newInstance();
System.out.println("rockMan = " + rockMan);
}
通过上面的示例,我们知道通过反射可以获取到给定类的Class对象,进而创建其实例。
扩展思考
Tips
如果我们用Class类,反射创建Class类的对象,将会怎样?
结果
此时运行将会抛出异常:
Exception in thread "main" java.lang.IllegalAccessException: Can not call newInstance() on the Class for java.lang.Class
原因
Class类的源码的newInstance()方法有如下判断
@CallerSensitive
public T newInstance()
throws InstantiationException, IllegalAccessException {
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) {
// 此处判断:当前对象是都就是Class本身,如果是,直接抛出异常。
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
....
}