1. 类加载器
1.1 作用
- 前期写的Java代码,属于源代码,后期要进行运行,首先需要将这个源代码进行编译,编译完成之后会形成一个.class文件,这个.class文件就是字节码文件,后期进行运行的时候,就需要将这个字节码文件加载到内存中,要把这个字节码文件加载到内存中就需要类加载器来完成
- 也就是说,类加载器就是负责将.class文件加载到内存中
1.2 类的加载时机问题
- 一个类什么时候被加载到内存?
- 创建类的实例(即对象)
- 调用类的类方法
- 访问类或者接口的类变量,或者为该类变量赋值
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
1.3 类的加载过程
- 一个类通过类加载器,将其加载到内存是需要经过很多个阶段的。大致可以分为
- 加载
- 通过包名+类名,获取这个类,准备用流进行传输
- 在这个类加载到内存中
- 加载完毕创建一个class对象,这个Class对象就是对这个类的字节码文件进行描述。Java语言是面向对象的语言,在Java看来万物皆对象,因此一个字节码文件Java也提供了对应的类对其进行描述,这个类就是Class
- 链接
- 验证
- 确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全
- 准备
- 负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值
- 解析
- 初始化
- 根据程序员通过程序制定的主观计划去初始化类变量和其他资源
- 总结
- 当一个类被使用的时候,才会被加载到内存
- 类加载的过程:加载、验证、准备、解析、初始化
1.4 分类
- 分类
- Bootstrap class loader:启动类加载器
- 虚拟机的内置类加载器,通常表示为null,并且没有父null
- Platfrom class loader:平台类加载器
- System class loader:系统类加载器
- 类加载器存在逻辑上的继承关系
- System的父加载器为Platform
- Platform的父加载器为Bootstrap
- 逻辑上的继承关系
- 没有通过extends关键字去指定某一个类加载器对应的父类加载器,但是他们的确是存在继承关系的,这是Java中的一种的机制,在类加载器这里可以看到
- 代码演示
public class ClassLoaderDemo1 {
public static void main(String[] args) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader classLoader1 = systemClassLoader.getParent();
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println("系统类加载器" + systemClassLoader);
System.out.println("平台类加载器" + classLoader1);
System.out.println("启动类加载器" + classLoader2);
}
}
1.5 双亲委派模型
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
1.6 ClassLoader中的两个方法
- Java语言的是面向对象的,万物皆对象。类加载器其实也是一个对象,在Java中就提供了一个类对其进行描述,这个类就是ClassLoader
- 方法介绍
方法名 |
说明 |
public static ClassLoader getSystemClassLoader() |
获取系统类加载器 |
public InputStream getResourceAsStream(String name) |
加载某一个资源文件 |
public class ClassLoaderDemo2 {
public static void main(String[] args) throws IOException {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
Properties prop = new Properties();
prop.load(is);
System.out.println(prop);
is.close();
}
}
2. 反射
2.1 概述
- 本质上
- 反射机制
- 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
- 对于任意一个对象,都能够调用它的任意属性和方法;
- 这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
- 如何我们可以获取到一个类的字节码文件对象,那么我们就可以从这个字节码文件中解析出来这个类中的成员,然后在使用成员。Java是面向对象的,万物皆对象,因此在Java看来一个类的构造方法是一对象,成员变量也是对象,成员方法也是对象。那么Java就提供了对应的类对其进行描述:Constructor、Field、Method。当我们获取到的对应的成员对象以后,就可以调用成员对象中的方法使用对应的成员
- 反射学习思路
- 首先获取一个类的字节码文件对象
- 调用字节码文件对象(Class)的方法获取类的指定的成员对象(构造方法,成员变量,成员方法)
- 调用对应的成员对象的方法使用类中的成员
2.2 获取Class对象
- 获取Class对象的三种方式
- 通过Class类中的静态方法forName来进行获取
- 通过类的class属性来获取,即类名.class
- 通过对象名.getClass()方法
- 三种方式获取的是同一个Class对象,因为一个类的字节码文件只有一个,所以一个类的字节码文件对象只有一个
- 代码演示
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void study(){
System.out.println("学生在学习");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
Class clazz = Class.forName("com.itheima.myreflect2.Student");
System.out.println(clazz);
Class clazz2 = Student.class;
System.out.println(clazz2);
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz3);
System.out.println(clazz == clazz2);
System.out.println(clazz2 == clazz3);
}
}
2.3 获取构造方法对象
方法名 |
说明 |
Constructor<?>[] getConstructors() |
返回所有公共构造方法对象的数组 |
Constructor<?>[] getDeclaredConstructors() |
返回所有构造方法对象的数组 |
Constructor getConstructor(Class<?>… parameterTypes) |
返回单个公共构造方法对象 |
Constructor getDeclaredConstructor(Class<?>… parameterTypes) |
返回单个构造方法对象 |
- 常用的是第四种
- parameterTypes:表示的是构造方法参数对应的Class类型
- 代码演示
public class Student {
private String name;
private int age;
private Student(String name) {
System.out.println("name的值为:" + name);
System.out.println("private...Student...有参构造方法");
}
public Student() {
System.out.println("public...Student...无参构造方法");
}
public Student(String name, int age) {
System.out.println("name的值为:" + name + "age的值为:" + age);
System.out.println("public...Student...有参构造方法");
}
}
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
}
private static void method4() throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class.forName("com.itheima.myreflect3.Student");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
System.out.println(constructor);
}
private static void method3() throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class.forName("com.itheima.myreflect3.Student");
Constructor constructor1 = clazz.getConstructor();
System.out.println(constructor1);
Constructor constructor2 = clazz.getConstructor(String.class, int.class);
System.out.println(constructor2);
Constructor constructor3 = clazz.getConstructor(int.class);
System.out.println(constructor3);
}
private static void method2() throws ClassNotFoundException {
Class clazz = Class.forName("com.itheima.myreflect3.Student");
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
private static void method1() throws ClassNotFoundException {
Class clazz = Class.forName("com.itheima.myreflect3.Student");
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
2.4 使用构造方法对象
方法名 |
说明 |
T newInstance(Object…initargs) |
根据指定的构造方法创建对象 |
setAccessible(boolean flag) |
设置为true,表示取消访问检查 |
- initargs: 表示的就是给构造方法所传递的具体的数据(实际参数)
- 代码演示
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
}
private static void method4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class clazz = Class.forName("com.itheima.myreflect3.Student");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance("zhangsan");
System.out.println(student);
}
private static void method3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clazz = Class.forName("com.itheima.myreflect3.Student");
Student student = (Student) clazz.newInstance();
System.out.println(student);
}
private static void method2() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {