Java 类加载器 & 反射

1 类加载器

1.1 类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

  • 加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
  • 连接:
    验证 –> 是否有正确的内部结构,并和其他类协调一致。
    准备 –> 负责为类的静态成员分配内存,并设置默认初始化值。
    解析 –> 将类的二进制数据中的符号引用替换为直接引用。
  • 初始化:就是我们以前讲过的初始化步骤。
1.2 类初始化时机
  1. 创建类的实例
  2. 类的静态变量,或者为静态变量赋值
  3. 类的静态方法
  4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  5. 初始化某个类的子类
  6. 直接使用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

猜你喜欢

转载自blog.csdn.net/lihaogn/article/details/81227465