一、类加载器
类加载器:用于将字节码文件加载到内存中
二、类加载过程
当我们的程序中要使用类的时候,如果类还没有被加载到内存中,那么类加载器会对该类进行加载、链接、初始化这三步加载进内存中
1、加载
-
通过类的包名+类名获取该类的二进制字节流,准备用流进行传输 -
将该类加载到运行时数据区 -
在内存中创建一个Class对象,该对象作为这个类的各种数据的访问入口
2、链接
将类的二进制数据合并到JRE中
-
验证:确保加载信息符合JVM规范,保证虚拟机安全 -
准备:为类的静态变量在方法区分配内存,并设置类变量默认初始值 -
解析:将虚拟机常量池内的符号引用替换为直接引用
3、初始化
初始化就需要由虚拟机控制,到了初始化阶段才真正执行java代码,类初始化的主要工作是为静态变量赋程序设定的初始值,也就是执行类构造器
方法的过程
三、类的主动引用
-
实例化对象 -
调用静态变量,或者是给静态变量进行赋值 -
调用静态方法 -
运行器运行 -
通过反射机制强制性的对类或接口的实现类进行实例化 -
实例化子类对象
四、类加载器的分类
类加载器分类主要分为两类:
-
JVM内置的类加载器:分别加载不同目录下的class文件 -
Bootstrap ClassLoader启动类/引导类/根类加载器:负责加载Java核心类,比如:String、Math、System等等。被加载的类都保存在 /jre/lib/rt.jar
中 -
Extension ClassLoader扩展类加载器:负责jre的扩展目录中jar包的加载,被加载的类都保存在 /jre/lib/ext
目录下 -
App ClassLoader应用类/系统类加载器:负责在jvm启动的时候加载来自java命令的class文件,以及classpath变量所指定的jar包和类路径,第三方jar包也会被加载 -
用户自定义的类加载器:负责的加载目录自己决定
五、双亲委派模式
双亲委派模式:如果一个类加载器收到了类加载请求,它不会先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,请求最终到达最顶层的启动类加载器,如果父类加载器可以完成加载任务,就成功返回,否则子加载器才会尝试自己加载
六、反射
1、反射概述
反射:在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法,这种动态获取程序信息以及动态调用对象的功能称之为Java语言的反射机制。被private封装的资源只能类内部访问,外部不行,但反射能直接操作类私有属性,反射可以在运行时获取一个类的所有信息(成员变量、成员方法、构造方法等),并且可以操纵类的属性、方法、构造器等
想要通过反射机制获取操纵一个类的所有资源,需要利用类加载器加载class字节码文件时创建的对应的Class对象。
2、获取Class对象
获取Class对象三种方式:
-
类名.class -
对象名.getClass() -
Class.forName(包名+类名)
2.1、Class.forName()
代码示例
public static void forNameHandler() throws Exception{
// 1、通过Class对象中的静态方法获取User对应的Class对象
Class clazz = Class.forName("cn.com.codingsir.reflect.User");
}
2.2、类名.class
代码示例
public static void classHandler(){
// 1、通过类名获取class对象
Class clazz = User.class;
}
2.3、对象.getClass()
代码示例
public static void getClassHandler(){
// 1、实例化User对象
User user = new User();
// 2、获取Class对象
Class clazz = user.getClass();
}
3、获取构造器
3.1、获取所有公共构造器
User.java
代码示例
package cn.com.example15;
public class User {
public int id;
public String userName;
public String password;
private String role;
public User(){}
public User(int id,String userName,String password,String role){
this.id = id;
this.userName = userName;
this.password = password;
this.role = role;
}
private User(String role){
this.role = role;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
private void accessableHandler(){
System.out.println("这是一个私有成员方法");
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + ''' +
", password='" + password + ''' +
", role='" + role + ''' +
'}';
}
}
代码示例
/**
* 获取所有构造器
*/
public static void findConstructors(){
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有的构造器不包含私有
Constructor[] constructors = clazz.getConstructors();
// 3、遍历
for (Constructor constructor : constructors) {
// public cn.com.example15.User()
// public cn.com.example15.User(int,java.lang.String,java.lang.String)
System.out.println(constructor);
}
}
3.2、获取无参构造器
代码示例
/**
* 获取无参构造器
*/
public static void findConstructorsNoParameter() throws Exception {
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有的构造器不包含私有
Constructor constructor = clazz.getConstructor();
// 3、运行构造器
User user = (User)constructor.newInstance();
System.out.println(user); // User{id=0, userName='null', password='null'}
}
3.3、获取有参构造器
代码示例
/**
* 获取有参构造器
*/
public static void findConstructorParameter() throws Exception {
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有的构造器不包含私有
// 必须指定参数类型对应的class,如果参数是int,那么必须是int.class
Constructor constructor = clazz.getConstructor(int.class,String.class,String.class,String.class);
// 3、运行构造器
User user = (User)constructor.newInstance(1001,"admin","admin","user");
System.out.println(user); // User{id=1001, userName='admin', password='admin', role='user'}
}
4、暴力反射
反射里的Constructor、Field、Method三个类都有一个getDeclaredXxx方法,可以不受限制的获取私有构造器、属性、方法调用。通过该方法获取私有成员,会自动的访问类的isAccessable,默认是false,如果想获取,那么调用setAccessable设置为true,就可以对类中的私有成员操作了。
代码示例
/**
* 获取所有构造器包含私有
*/
public static void findConstructors(){
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有的构造器
Constructor[] constructors = clazz.getDeclaredConstructors();
// 3、遍历
for (Constructor constructor : constructors) {
// private cn.com.example15.User(java.lang.String)
// public cn.com.example15.User(int,java.lang.String,java.lang.String,java.lang.String)
// public cn.com.example15.User()
System.out.println(constructor);
}
}
/**
* 获取指定私有构造器
*/
public static void findConstructorParameter()throws Exception{
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有的构造器不包含私有
Constructor constructor = clazz.getDeclaredConstructor(String.class);
// 设置为true
constructor.setAccessible(true);
// 3、实例化对象
System.out.println(constructor.newInstance("admin")); // User{id=0, userName='null', password='null', role='admin'}
}
5、实例化对象
在不手动调用构造器的前提下,利用反射机制直接实例化对象
代码示例
public static void newInstanceHandler() throws IllegalAccessException, InstantiationException {
Class clazz = User.class;
// 实例化对象,通过该方式,前提构造器访问修饰符必须是公共的
User user = (User) clazz.newInstance();
System.out.println(user); // User{id=0, userName='null', password='null', role='null'}
}
6、成员变量
6.1、获取所有公共属性
代码示例
/**
* 获取所有公共属性
*/
public static void findFields(){
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有公共的属性
Field[] fields = clazz.getFields();
for (Field field : fields) {
/**
* public int cn.com.example15.User.id
* public java.lang.String cn.com.example15.User.userName
* public java.lang.String cn.com.example15.User.password
*/
System.out.println(field);
}
}
6.2、获取所有属性
代码示例
/**
* 获取所有属性
*/
public static void findFieldsAccessable(){
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
/**
* public int cn.com.example15.User.id
* public java.lang.String cn.com.example15.User.userName
* public java.lang.String cn.com.example15.User.password
* private java.lang.String cn.com.example15.User.role
*/
System.out.println(field);
}
}
6.3、获取指定属性
代码示例
/**
* 获取指定属性
*/
public static void findField() throws Exception{
// 1、获取Class对象
Class clazz = User.class;
// 2、获取userName属性
Field userName = clazz.getField("userName");
// 3、实例化对象
User user = (User)clazz.newInstance();
// 4、设置属性值
userName.set(user,"admin");
System.out.println(user); // User{id=0, userName='admin', password='null', role='null'}
}
7、成员方法
7.1、获取所有公共成员方法
/**
* 获取所有公共成员方法
*/
public static void findMethods(){
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有公共成员方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
/**
* public java.lang.String cn.com.example15.User.toString()
* public void cn.com.example15.User.setRole(java.lang.String)
* public java.lang.String cn.com.example15.User.getRole()
* public final void java.lang.Object.wait() throws java.lang.InterruptedException
* public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
* public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
* public boolean java.lang.Object.equals(java.lang.Object)
* public native int java.lang.Object.hashCode()
* public final native java.lang.Class java.lang.Object.getClass()
* public final native void java.lang.Object.notify()
* public final native void java.lang.Object.notifyAll()
*/
System.out.println(method);
}
}
7.2、获取所有成员方法
/**
* 获取所有成员方法
*/
public static void findMethodsAccessable(){
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有成员方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
/**
* public java.lang.String cn.com.example15.User.toString()
* public void cn.com.example15.User.setRole(java.lang.String)
* public java.lang.String cn.com.example15.User.getRole()
* private void cn.com.example15.User.accessableHandler()
*/
System.out.println(method);
}
}
7.3、获取无参成员方法
/**
* 获取指定的无参成员方法
*/
public static void findMethodNoParameter()throws Exception{
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有公共成员方法
Method method = clazz.getMethod("getRole");
// 3、实例化对象
User user = (User)clazz.newInstance();
// 4、调用方法
Object role = method.invoke(user);
System.out.println(role);
}
7.4、获取有参成员方法
/**
* 获取指定的有参成员方法
*/
public static void findMethod()throws Exception{
// 1、获取Class对象
Class clazz = User.class;
// 2、获取所有公共成员方法
Method method = clazz.getMethod("setRole",String.class);
// 3、实例化对象
User user = (User)clazz.newInstance();
// 4、调用方法
method.invoke(user,"admin");
}
8、泛型擦除
代码示例
/**
* 泛型擦除
* 定义一个String泛型类型的List集合,通过反射实现添加Integer类型的数据到集合中
*/
public static void method() throws Exception {
// 1、创建List集合,指定泛型类型为String
List<String> list = new ArrayList<>();
// 2、添加数据
list.add("admin");
list.add("user");
list.add("guest");
// 3、获取List集合的Class对象
Class clazz = list.getClass();
// 4、获取方法
Method add = clazz.getMethod("add",Object.class);
// 5、运行方法
add.invoke(list,24);
// 6、输出集合
System.out.println(list); // [admin, user, guest, 24]
}
9、配置文件
把一个类的类名和方法名添加到properties文件中,通过反射机制读取内容并调用方法
user.properties
className = cn.com.example15.User
methodName = toString
代码示例
public static void propertiesHandler() throws Exception {
// 1、创建输入流
FileReader fileReader = new FileReader("src/cn/com/codingsir/user.properties");
// 2、实例化Properties对象
Properties properties = new Properties();
// 3、读取数据并保存
properties.load(fileReader);
// 4、获取配置文件内容
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
// 5、获取Class对象
Class clazz = Class.forName(className);
// 6、实例化对象
User user = (User)clazz.newInstance();
// 7、获取Method对象
Method method = clazz.getMethod(methodName);
// 8、调用方法
String str = (String)method.invoke(user);
System.out.println(str); // User{id=0, userName='null', password='null', role='null'}
}
原文始发于微信公众号(数字游民PG):Java反射开启暴力反射及泛型擦除,以及底层原理和性能分析、优化
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/174036.html