直通大厂必考题系列:深入详解Java反射机制与底层实现原理
Java面试的时候经常会被问到Java反射机制,尤其喜欢问:
- Java反射机制?
- 为什么要用反射机制?
- Java反射机制的原理?
- Java反射机制用在什么地方等等?
今天主要分享以上内容,详解Java反射机制的底层实现@mikechen
Java反射机制是什么?
Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。
对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法。
为什么要用反射?
Java Reflection功能非常强大,并且非常有用,比如:
- 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等;
- 获取任意对象的属性,并且能改变对象的属性;
- 调用任意对象的方法;
- 判断任意一个对象所属的类;
- 实例化任意一个类的对象;
- 通过反射我们可以实现动态装配,降低代码的耦合度,动态代理等。
Java反射机制原理
Java反射操作的是java.lang.Class对象,所以要理解Java反射机制,就需要搞懂Class对象。
比如举一个简单的例子,创建一个对象:
MikeChen mikechen= new MikeChen();
在运行上面语句的时候,首先 JVM 启动,代码会编译成一个 .class 文件,然后被类加载器ClassLoader加载进 JVM 的内存中,并为之创建一个 java.lang.Class 对象。
我们的 MikeChen类会加载到方法区中,创建了的 MikeChen类的 Class 对象会到堆中。
理解 Java 的反射机制就是要理解 Class 类。
每个类的运行时的类型信息,用 Class 对象表示,又或者称之为字节码对象。
Class 文件的整体结构如下图所示:
它包含了与类相关的信息,而实例对象就是通过 Class 对象来创建的。
获取 Class 对象的方式:
- 实例对象调用 Object 类的getClass()方法;
- 通过属性类名.class直接获取;
- 调用 Class 类的forName()方法;
- 使用类加载器 ClassLoader 的getSystemClassLoader().loadClass()方法。
package com.mikechen.reflection;
import com.mikechen.model.Person;
public class ReflectionTest {
public static void main(String[] args) throws Exception {
//1. 实例对象.getClass()
Person person = new Person();
Class clz1 = person.getClass();
System.out.println(clz1);
//2,类名.class属性
System.out.println(Person.class);
//3. Class.forName()
Class clz2 = Class.forName("com.mikechen.reflection.Person");
System.out.println(clz2);
}
}
以上三种方式都能获取 Person 类的字节码对象,但同时也存在区别:
- 方法1:需要创建一个实例对象才能获取类的信息;
- 方法2:则需要导入包否则无法通过编译;
- 方法3:只需传入类名的字符串,这个类名是类完整路径;
我们一般平时是通过new的形式创建对象实际上就是通过这些Class来创建的,只不过这个class文件是编译的时候就生成的,程序相当于写死了给jvm去跑。
反射是什么呢?当我们的程序在运行时,需要动态的加载一些类这些类可能之前用不到,所以不用加载到jvm,而是在运行时根据需要才加载。
Java反射的应用场景
面向开发,反射应用最广泛的是中间件和框架,比如:
- JDBC的Class.forName(driverClass)加载驱动;
- Spring MVC 通过反射调用 controller 的方法,动态代理处理请求;
- Spring IOC 容器,在创建 Bean 实例时和依赖注入时的反射。
- RMI 反序列化,反射调用远程方法;
- RPC Dubbo动态代理利用;