反射
我自己之前学习过深度学习相关内容,使用mmdetection时就感受到了这种感觉,就是一整个模型架构只需要修改配置文件的内容就可以瞬间搭建不同的模型、调整不同的训练策略等。java的反射应该和这个类似。
反射机制
- 反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
- 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象) ,这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一-面镜子,透过这个镜子看到类的结构,所以,形象地称之为反射。
- 这种机制遵循了设计原则中的开闭原则,尽量在不修改源码的情况下扩展功能。只需要修改配置文件中的少部分信息,就能组建不同的程序。
优点
可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。缺点
使用反射基本是解释执行,对执行速度有影响。
反射相关的类
- java.lang.Class代表一个类, Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method 代表类的方法,Method对象表示某个类的方法
- java.lang.reflect.Field 代表类的成员变量
- java.lang.reflect.Constructor 代表类的构造方法
Class 类
- Class也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class类对象,在内存中只有一份, 因为类只加载一次
Class<?> catClass = Class.forName("Reflection.Cat");
Class<?> catClass2 = Class.forName("Reflection.Cat");
System.out.println(catClass.hashCode() + "\n" + catClass2.hashCode());
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类的完整结构,通过一系列API
- Class对象是存放在堆的
- 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等) https://www.zhihu.com/question/38496907
System.out.println(catClass); // 输出catClass表示的是哪个类
System.out.println(catClass.getClass()); // 输出catClass本身的运行类型-->Class
获取Class类字节码文件的方式
- Class c = 实例对象.getClass()
- Class c = Class.forName(“完整的类名”)
- Class c = 任何类.class
重点
如果你只是希望一个类的静态代码块执行,其它代码一律不执行,你可以使用: Class. forName(“完整类名”); 该方法的执行会导致类加载,类加载时,静态代码块执行。
Class 类常用方法
一定要注意: newInstance ()底层调用的是该类型的无参数构造方法
哪些类型有Class对象
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface :接口
- 数组
- enum :枚举
- annotation :注解
- 基本数据类型
- void
反射调用优化-关闭访问检查
- Method和Field、Constructor对象都有setAccessible()方法
- setAccessible作用是启动和禁用访问安全检查的开关
- 参数值为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查
资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。使用以下这种方式的时候,属性配置文件xxx. properties
得在
src 目录下。资源绑定器只能綁定xxx. properties
文件。并且这个文件必须在src下。文件扩展名也必须是properties
并且在写路径的时候,路径后面的扩展名不能写。
// 配置文件在: src/Reflection/demo.properties
ResourceBundle bundle = ResourceBundle.getBundle("Reflection/demo");
String height = bundle.getString("height");
System.out.println(height);
资源绑定器中还有别的方法很实用!
补充 用以下方法可以获取文件路径,并且很通用
string path = Thread.currentThread().getContextClassLoader().getResource("写相对路径,但是这个相对路径从src出发开始找").getPath
string path = Thread.currentThread().getContextClassLoader().getResource ("abc").getpath() ; //必须保证src下有abc文件
属性 Field
当我们拿到Class了之后,就可以通过Class获取该类的属性字段了。