类加载器概述
一、类的加载
(1)类的加载
- 当Java程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三步来实现对这个类进行初始化。
- 加载:就是指将类的class文件读入内存,并为之创建一个Class对象。任何类被使用时,系统都会建立一个Class对象。
- 连接:
- 验证:是否有正确的内部结构,并和其他类协调一致。
- 准备:负责为类的静态成员分配内存,并设置默认初始化值(类的静态成员随着类的加载而加载)。
- 解析:将类的二进制数据中的符号引用替换为直接引用。
- 初始化:就是以前接触过的普通的初始化步骤。
二、类的初始化时机
(1)类的初始化时机:类在什么时候做初始化工作呢?
- 创建类的实例的时候
- 访问类的静态变量,或者为静态变量赋值的时候
- 调用类的静态方法的时候
- 使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象的时候
- 初始化某个类的子类的时候(先有父类才能有子类)
- 直接使用 java.exe 命令来运行某个主类的时候
三、类加载器
(1)类加载器的作用:
- 负责将 .class文件 加载到内存中,并为之生成对应的Class对象。
- 虽然我们不需要关心类加载机制,但是了解这个类加载机制我们就能更好的理解程序的运行。
(2)类加载器的组成:
- 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包和类路径。
(3)通过这些描述,我们就可以知道我们常用的东西的加载都是由谁(系统类加载器)来完成的。到目前为止,我们已经知道把class文件加载到内存中了,那么,如果我们仅仅站在这些class文件的角度,我们该如何来使用这些class文件中的内容呢?这就是反射要研究的内容。
四、反射
(1)JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法;这种动态获取的信息以及动态调用对象的方法的功能 称为java语言的反射机制。
(2)要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法。所以,先要获取到每一个字节码文件对应的Class类型的对象。
/*
* 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
* Person p = new Person();
* p.使用
* 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
* Class类:
* 成员变量 ——> Field 类 ——> 调用类的方法来获取成员变量
* 构造方法 ——> Constructor 类 ——> 调用类的方法来获取构造方法
* 成员方法 ——> Method 类 ——> 调用类的方法来获取成员方法
* 获取class文件对象的方式:
* A: Object类的 getClass() 方法。 通过对象名:Person p = new Person(); Class c = p.getClass();
* B: 数据类型的静态属性 class。 通过类名:Class c2 = Person.class; 任意数据类型都具备一个class静态属性,看上去要比第一种方式简单。
* C: Class类中的静态方法:public static Class forName(String className)。将全路径类名作为字符串传递给Class类中的静态方法forName即可:Class c3 = Class.forName("cn.itcast_01.Person");
*
* 一般我们到底使用谁呢?
* A:自己玩 任选一种,第二种比较方便
* B:开发 第三种:为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。
*/
五、获取class文件对象的三种方式
1、获取class文件对象的三种方式举例
(1)Person类
package cn.itcast_01;
public class Person {
private String name;
int age;
public String address;
public Person() {
}
private Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void show() {
System.out.println("show");
}
public void method(String s) {
System.out.println("method " + s);
}
public String getString(String s, int i) {
return s + "---" + i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address
+ "]";
}
}
(2)获取class文件对象的三种方式
package cn.itcast_01;
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 获取方式1
Person p = new Person();
Class c = p.getClass();
Person p2 = new Person();
Class c2 = p2.getClass();
System.out.println(p == p2);// false
System.out.println(c == c2);// true
// 获取方式2
Class c3 = Person.class;
// int.class;
// String.class;
System.out.println(c == c3);// true
// 获取方式3
// ClassNotFoundException
Class c4 = Class.forName("cn.itcast_01.Person");
System.out.println(c == c4);// true
}
}