说明:本文是校招复习系列文章,参考文献做统一说明!
整体目录详见:校招复习目录
另参考:
Java基础之—反射(非常重要)
大白话说Java反射
深入分析Java方法反射的实现原理
1. 反射介绍
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
反射机制实际上就是上帝模式,如果说方法的调用是 Java 正确的打开方式,那反射机制就是上帝偷偷开的后门,只要存在对应的class,一切都能够被调用。
2. 反射原理
3. 获取Class对象的三种方式
使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
如果我们动态获取到这些信息,我们需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序。Java 提供了两种方式获取 Class 对象:
-
知道具体类的情况下可以使用:
需要导入类的包
// Class alunbarClass = TargetObject.class; Class stuClass2 = Student.class; System.out.println(stuClass == stuClass2);
-
对象.getClass:
第一种对象都有了还要反射干什么 ?
Student stu1 = new Student();//new 产生一个Student对象,一个Class对象。 Class stuClass = stu1.getClass();//获取Class对象 System.out.println(stuClass.getName());
-
通过
Class.forName()
传入类的路径获取,常用:// Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject"); //注意此字符串必须是真实路径,就是带包名的类路径,包名.类名 Class stuClass3 = Class.forName("fanshe.Student"); System.out.println(stuClass3 == stuClass2);
-
实例-1:
// 获取class
Class<?> demo2 = Class.forName("jstudy.basic.Demo2");
// 创建实例
Object o = demo2.newInstance();
// 获取方法集合
Method[] me = demo2.getDeclaredMethods();
for (Method m:me){
System.out.println(m);
}
// 找到某一个方法,但是怎么去使用,这是一个问题?
Method testForNum = demo2.getDeclaredMethod("testForNum");
实例-2:
在未运行时就已经确定了要运行的类(Apple) ,
Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);
在运行时通过字符串值才得知要运行的类(com.chenshuyi.reflect.Apple)。所以反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
Class clz = Class.forName("com.chenshuyi.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
// 利用 invoke 方法调用方法
method.invoke(object, 14); //存进去
Method getPriceMethod = clz.getMethod("getPrice");
// 利用 invoke 方法调用方法
System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
4. 静态编译和动态编译
- 静态编译: 在编译时确定类型,绑定对象
- 动态编译: 运行时确定类型,绑定对象
两者的区别在于,动态编译可以最大程度地支持多态,而多态最大的意义在于降低类的耦合性,因此反射的优点就很明显了:解耦以及提高代码的灵活性。
5. 反射机制的优缺点
- 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
- 缺点:
- 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。
- 安全问题:让我们可以动态操作改变类的属性同时也增加了类的安全隐患。
6. 反射的应用场景
反射是框架设计的灵魂。
在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关。例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。
举例:
- 我们在使用 JDBC 连接数据库时使用
Class.forName()
通过反射加载数据库的驱动程序;利用反射将数据库的表字段映射到java对象的getter/setter方法; - Spring 框架的 IOC(动态加载管理 Bean)创建对象以及 AOP(动态代理)功能都和反射有联系;
- 动态配置实例的属性;
- 反编译:.class–>.java