面试遇到这个问题,必须好好的想想如何回答这个问题,我就是这么回答的。害
面试官:反射是什么?
我:在Java的反射机制中是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。
面试官:哦?有什么好处?
我:怎么说呢,跟多态是的,比如在Java程序中许多对象在运行是都会出现两种类型:编译时类型和运行时类型。其中,编译时类型由声明对象时使用的类型来决定,运行时的类型由实际赋值给对象的类型决定 。比如
People = = new Man();
程序在运行的时候,有时候需要注入外部资源,那么这个外部资源在编译时是People,如果想要它的运行时类型中的某个方法,为了解决这些问题,程序在运行时发现对象和类的真实信息,但是编译时根本无法预知该对象和类属于哪些类,程序只能靠运行时信息来发现该对象和类的信息,那就要用到反射了。
面试官:举几个反射的API
我:
- Class 类:反射的核心类,可以获取类的属性,方法等信息。
- Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
- Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
- Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法
面试官:获取class对象的三种方式?
我:
Student student = new Student(); *// 这一new 产生一个Student对象,一个Class对象。*
Class studentClass2 = Student.class; // 调用某个类的 class 属性来获取该类对应的 Class 对象
Class studentClass3 = Class.forName("com.reflect.Student") // 使用 Class 类中的 forName() 静态方法 ( 最安全 / 性能最好 )
面试官:三者区别?
我:
- Class.class 的形式会使 JVM 将使用类装载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回 Class 对象。
- Class.forName() 的形式会装入类并做类的静态初始化,返回 Class 对象。
- getClass() 的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的 Class 对象。
静态属性初始化是在加载类的时候初始化,而非静态属性初始化是 new 类实例对象的时候初始化。它们三种情况在生成 Class 对象的时候都会先判断内存中是否已经加载此类。
面试官:ClassLoader呢?
我:ClassLoader就是遵循双亲委派模型最终调用启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制流后放到JVM中,加载的类默认不会进行初始化。
而Class.forName()会静态初始化,那么看源码:
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
// 这里的true,就是初始化
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
// initialize:是否初始化
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
面试官:
面试官:除了通过反射创建对象,还有?
我:new呗,clone一个呗
面试官:反射都有哪些应用场景
我:我可以说Spring,Dubbo,RocketMQ吗?这些优秀的框架背后都用到了反射,这说明,反射的优点之一灵活,提高了代码的灵活度,但同时性能受损。因为反射要进行一系列的解释操作。