JavaSE - Note11 Reflect & Path
反射机制
通过 Java 语言中的反射机制,可以操作字节码文件、代码片段(class 文件),让程序更加灵活
java.lang.reflect.*
相关重要类
java.lang.Class
代表整个字节码(一个类型,整个类),要操作一个类的字节码,首先需要获取到这个类的字节码文件,有以下三种方式:
static Class
forName(String className) - 静态方法
- 方法参数是一个字符串(需要有包路径的完整类名)
- 方法会导致类加载,若只想执行类中 static 静态代码块,可以这么使用
1
2Class c1 = Class.forName("java.lang.String");
// 代表 java.lang.String.class 文件Class
getClass() - Java 中任何一个对象都有 getClass 方法
1
2
3
4
5String s = "abc";
Class x = s.getClass();
// x 代表 String.class 字节码文件、String 类型
System.out.println(c1 == x); // true(内存地址)
// c1 与 x 同时指向方法区中的 String.class 字节码文件Java 语言中任何一种类型(包括基本数据类型),它都有 .class 属性
1
Class z = int.class; // z 代表 int 类型
获取字节文件作用
反射机制获取 Class,通过 Class 的 newInstance()
方法来实例化对象
newInstance() 方法后台调用了无参构造方法,需保证其存在
该方法在 JDK 9 之后已过时(此处为了演示),有替代方案
1
2
3Class c = Class.forName("[package].[className]");
Object o = c.newInstance();
System.out.println(o);
优点:更为灵活
通过 properties 配置文件配置 className,创建对应类时,只需要修改配置文件中的类名,然后通过 io 流读取,再通过反射机制创建类
Java 代码写一遍,在不改变 Java 源码的基础上,可以做到不同对象的实例化(符合 OCP 开放原则:对扩展开放,对修改关闭)
classInfo.properties
1 |
|
Test.java
1 |
|
java.lang.reflect.Field
代表字节码中的属性字节码(类中成员变量)
Field getField(String name)
返回一个 Field 对象(仅支持 public 修饰变量)
Field[] getFields()
返回一个 Field 数组(仅支持 public 修饰变量)
若要获取所有类型权限符修饰的变量,使用
Field getDeclaredField()
或Field getDeclaredFields()
String getName()
返回由此 Field 对象表示的字段的名称
Class
getType() 返回一个标识字段的类对象
转换成 Class 便能获取类名/简单类名
Class 对象支持以下两种方法:
String getName()
返回类名
String getSimpleName()
返回简单的类名(不含包名)
int getModifiers()
返回修饰符(可能有多个,即为 int 类型,表示修饰符代号)
通过
java.lang.reflect.Modifier
中的static String toString(int mod)
方法进行转换Class 中也有此方法
Example
实现成员变量反编译
Student.java
1 |
|
Test.java
1 |
|
获取对象属性
void set(Object obj, Object value)
将指定对象 obj 上的此 Field 赋一个值 value
Object get(Object obj)
获取指定对象的 Field 值
1 |
|
打破封装(反射机制缺点,可能带来安全性问题)
通过
Field.setAccessible(true)
开启私有属性的访问权
java.lang.reflect.Method
代表字节码中的方法字节码(类中方法)
常用方法类似于 Field
Class
getReturnType() 获取方法返回值类型,(调用 Class 的
getSimpleName()
)Class
[] getParameterTypes() 获取参数列表类型,(循环调用 Class 的
getSimpleName()
)
调用对象方法
方法 getDeclaredMethod(String name, Class
获取对象:对象名;参数列表
Object invoke(Object obj, Object… args)
调用方法:对象;Method 方法名(调用函数);实参列表;返回值
1 |
|
*可变长度参数
类型... [name]
可传 0-n 个,且必须位于参数列表中最后一个(只能有一个)
可变长度参数可以当作一个数组来看待(有数组特征)
1 |
|
java.lang.reflect.Constructor
代表字节码中的构造方法字节码(类中构造方法)
类似于 Method
构造方法创建对象
1 |
|
获取父类与接口
1 |
|
文件路径
IDEA 路径
1 |
|
缺点:移植性差,IDEA 中默认的当前路径是 project 的根,离开了 IDEA,路径便无效
通用路径
前提:文件必须在类路径下(src 是类的根路径)(仅等同于类路径,真正的类路径在 IDEA 的 out 中)
1 |
|
- Thread.currentThread():当前线程对象
- getContextClassLoader():线程对象方法,可以获取当前线程的类加载器对象
- getResource(“classInfo.proerties”):类加载器对象方法,当前线程的类加载器默认从类的根路径下加载资源(此为根路径下的 classInfo.properties文件)
- getPath():获取路径
还可以直接以流的形式返回:
1 |
|
资源绑定器
java.util
包下提供了一个资源绑定器,便于获取属性配置文件中的内容
1 |
|
- 只能绑定
xxx.properties
- 必须放在类路径下
- 路径忽略扩展名