1 类加载器
1.1 类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
- 加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
- 连接:
验证 –> 是否有正确的内部结构,并和其他类协调一致。
准备 –> 负责为类的静态成员分配内存,并设置默认初始化值。
解析 –> 将类的二进制数据中的符号引用替换为直接引用。 - 初始化:就是我们以前讲过的初始化步骤。
1.2 类初始化时机
- 创建类的实例
- 类的静态变量,或者为静态变量赋值
- 类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
1.3 类加载器
负责将.class文件加载到内存中,并为之生成对应的class对象。
1.4 类加载器的组成
- Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载。比如System,String等。在JDK中JRE的lib目录下rt.jar文件中。
- Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录。
- System ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
2 反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
2.1 class类
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
获取Class对象的三种方式:
- 方式一:通过object类中的方法获取
Person p = new Person();
Class c = p.getClass();
- 方式二:通过 类名.class获取到字节码文件对象
Class c2 = Person.class;
- 方式三:通过class类中的方法
Class c3 = Class.forName("Person");
2.2 通过反射获取构造方法并使用
1)创建一个students类
package com.lihaogn;
public class Students {
private String name;
private int age;
private String sex;
// 构造方法
public Students() {
System.out.println("空参数构造函数方法");
}
public Students(String name) {
this.name = name;
System.out.println("带有String的构造方法");
}
// 私有的构造方法
private Students(String name, int age) {
this.name = name;
this.age = age;
System.out.println("带所有string,int的构造方法");
}
private Students(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("带所有string,int,string的构造方法");
}
// 成员方法
public void method1() {
System.out.println("没有返回值没有参数的方法");
}
public void method2(String name) {
System.out.println("没有返回值,有参数的方法 name= " + name);
}
public int method3() {
System.out.println("有返回值,没有参数的方法");
return 123;
}
public String method4(String name) {
System.out.println("有返回值,有参数的方法");
return "哈哈" + name;
}
// 私有方法
private void method5() {
System.out.println("私有方法");
}
@Override
public String toString() {
return "students [name = " + name + " ,age =" + age + ", sex =" + sex + "]";
}
}
2)获取构造方法
public static void main(String[] args) throws Exception {
// 获取Class对象
Class c = Class.forName("com.lihaogn.Students");// 包名.类名
// 获取所有的构造方法
// Constructor[] cons = c.getConstructors(); // 获取所有public修饰的构造方法
Constructor[] cons = c.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("------------------------");
// 获取一个构造方法
Constructor con1 = c.getConstructor(null);
System.out.println(con1);
//
Constructor con2 = c.getConstructor(String.class);
System.out.println(con2);
//
Constructor con3 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
//
Constructor con4 = c.getDeclaredConstructor(String.class, int.class, String.class);
System.out.println(con4);
}
运行结果:
private com.lihaogn.Students(java.lang.String,int,java.lang.String)
private com.lihaogn.Students(java.lang.String,int)
public com.lihaogn.Students(java.lang.String)
public com.lihaogn.Students()
------------------------
public com.lihaogn.Students()
public com.lihaogn.Students(java.lang.String)
private com.lihaogn.Students(java.lang.String,int)
private com.lihaogn.Students(java.lang.String,int,java.lang.String)
2.2.1 通过反射方式,获取构造方法,创建对象
// 1 获取class对象
Class class1=Class.forName("com.lihaogn.Students");
// 2 获取指定的构造方法
Constructor constructor=class1.getConstructor(String.class);
// 3 创建对象
Object object=constructor.newInstance("zhangsan");
System.out.println(object);
2.2.2 通过反射方式,获取私有构造方法,创建对象
// 1 获取class对象
Class class1=Class.forName("com.lihaogn.Students");
// 2 获取指定的构造方法
Constructor constructor=class1.getDeclaredConstructor(String.class,int.class,String.class);
// 3 暴力反射
constructor.setAccessible(true); // 取消Java语言访问检查
// 4 创建对象
Object object=constructor.newInstance("zhangsan",22,"man");
System.out.println(object);
2.3 通过反射获取成员变量并使用
// 1 获取class对象
Class class1=Class.forName("com.lihaogn.Students");
// 2 获取构造方法
Constructor constructor=class1.getConstructor(String.class);
// 3 通过构造方法,创建对象
Object obj=constructor.newInstance("zhangsan");
// 4 获取指定的成员变量
Field nameField=class1.getDeclaredField("name");
Field ageField=class1.getDeclaredField("age");
Field sexField=class1.getDeclaredField("sex");
// 5 暴力反射
nameField.setAccessible(true);
ageField.setAccessible(true);
sexField .setAccessible(true);
// 6 给指定对象的成员变量赋值或取值
System.out.println("name= "+nameField.get(obj));
System.out.println("age= "+ageField.get(obj));
System.out.println("sex= "+sexField.get(obj));
// 7 赋值
ageField.set(obj, 23);
sexField.set(obj, "man");
System.out.println("------------------");
System.out.println("name= "+nameField.get(obj));
System.out.println("age= "+ageField.get(obj));
System.out.println("sex= "+sexField.get(obj));
运行结果:
带有String的构造方法
name= zhangsan
age= 0
sex= null
------------------
name= zhangsan
age= 23
sex= man
2.4 通过反射获取成员方法并使用
// 1 获取class对象
Class class1 = Class.forName("com.lihaogn.Students");
// 2 获取构造方法
Constructor constructor = class1.getConstructor(String.class);
// 3 通过构造方法,创建对象
Object obj = constructor.newInstance("zhangsan");
// 4 获取指定的方法
Method method = class1.getMethod("method4", String.class);
// 5 执行找到的方法
Object result = method.invoke(obj, "zhangsan");
System.out.println("result= " + result);
运行结果:
带有String的构造方法
有返回值,有参数的方法
result= 哈哈zhangsan