类加载器
作用:将编译的.class文件加载进入jvm
Bootstrap ClassLoader 根类加载器
作用: 加载JDK、JRE的核心类:System、String
Extension ClassLoader 扩展类加载器
作用:负责jre-lib目录下的jar包或资源文件的加载
System ClassLoader 系统类加载器
作用:负责在JVM启动时加载来及java或javac的加载命令
一个.class文件只会对应一个字节码文件对象(Class类对象)
一个类的不同对象,也只会拥有同一个字节码文件对象
Class对象获取的三种方法
// 加载的字节码文件不存在项目路径中时(不是自己写的)
Class<?> aClass = Class.forName("com.huawei.java.wx.WXClient");
// 加载时该类只是被类加载器加载但是没有对象时
Class<WXClient> wxClientClass = WXClient.class;
// 已经有对象,但是要反推得到对应类的字节码文件对象
WXClient c1 = new WXClient("11");
Class<? extends WXClient> aClass1 = c1.getClass();
反射-Class对象三个重要对象
Field 对象- 类的属性对象
获取所有字段的方法:
1.得到类的所有public字段
Field[] getFields()
2. 返回类中所有的字段,包括:私、保、默、公
Field[] getDeclaredFields()
获取指定字段的方法:
1.获取某个"公有的"字段:
public Field getField(String fieldName);
2.获取某个字段(可以是私有的)
public Field getDeclaredField(String fieldName)
获取变量的类型:
Field.getType():返回这个变量的类型
Field.getGenericType():如果当前属性有签名属性类型就返回,否则就返回 Field.getType()
isEnumConstant() : 判断这个属性是否是枚举类
获取成员变量的修饰符
Field.getModifiers() 以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符
* private static final 2+8+16 = 26
*
* private : 2
* (default):0
* protected: 4
* public : 1
* static : 8
* final : 16
获取和修改成员变量的值
getName() : 获取属性的名字
get(Object obj) 返回指定对象obj上此 Field 表示的字段的值
set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
jdk8以上版本,想要危险操作时添加
旧JDK制作的库(JDK8及以下)运行在JDK9上会自动被标识为未命名模块,为了处理该警告,JDK9以上提出了一个新的JVM参数:--illegal-access。
该参数有四个可选值:
1.permit:默认值,允许通过反射访问,因此会提示像上面一样的警告,这个是首次非法访问警告,后续不警告
2.warn:每次非法访问都会警告
3.debug:在warn的基础上加入了类似e.printStackTrace()的功能
4.deny:禁止所有的非法访问除了使用特别的命令行参数排除的模块,比如使用--add-opens排除某些模块使其能够通过非法反射访问
因此解决的办法很简单,将其设置为deny,并添加--add-opens开启对应的允许非法反射访问的模块即可。
--illegal-access=deny --add-opens java.base/java.lang=ALL-UNNAMED
add-opens可以使模块中的包对其他模块开放,这样就可以在运行期使用深层反射访问该程序包中的所有成员类型。