JavaSE笔记_15

本文详细介绍了Java中的类加载器,包括加载时机、加载过程和类加载器的分类,强调了双亲委派机制的作用。同时,文章深入讲解了反射机制,如何构造对象、访问成员变量和方法,以及如何获取字节码对象。通过示例代码展示了如何利用反射进行操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、类加载器

1. 类加载器(Classloader):
  • 是Java运行时环境的一部分,负责动态加载Java类到Java虚拟机的内存空间中

2. 类的加载时机
  • 创建该类对象时
  • 使用该类的静态成员时
  • 通过反射创建对象时
  • 创建该类的子类对象时
  • 使用java命令,直接运行该类
3. 类的加载过程
       加载:
              将硬盘中的.class文件,由类加载器,通过该类的全类名(包名+类名)以字节的形式,加载到内存中的一个过程。
        验证:
            通过javac编译java文件,会进行第一个安全验证。
            再次验证字节码文件中,是否有威胁JVM安全的代码。
        准备:
            对静态成员进行默认初始化的工作。   【静态属于类】
            非静态成员,在创建对象时,才会默认初始化。  【非静态属于对象】
        解析:
            将类中的符号引用,替换成直接引用。
        初始化:
            就静态成员的默认初始化,替换成显示初始化。
4.类加载器的分类
  • 跟类加载器(Botstrap ClassLoader):加载JDK核心类
  • 扩展类加载器(Ext ClassLoader):加载JDK扩展类库的类
  • 应用城西类加载器(Application ClassLoader):加载用户自定义的类
  • 用户自定义类加载器(User ClassLoader)
5. 双亲委派机制

当某个类被加载时,入口是 Application ClassLoader,但是该类加载器不会直接加载,而是向其父类加载器(Ext ClassLoader)询问,该类也不会直接加载,而是再次向其父类加载器(Bootstrap ClassLoader)发起询问,如果该类是由跟类加载器负责,则有跟类加载器加载;否则回到其子类(Ext ClassLoader)判断是否为其负责,如果是则有该类加载器加载;否则回到其子类(Application ClassLoader)加载。

  • **目的:**防止用户自定义类覆盖JDK核心类
  • 方法:
    • getClassLoader() 获取类加载器对象
    • getResourceAsStream(String name) 以流的形式加载src下的配置文件name

二、反射

  • Java的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
  • 反射操作的是字节码文件
    • 字节码文件:是一种包含执行程序,由一序列 op 代码/数据对组成的二进制文件,是一种中间码;其中包含了该类的所有成员(包括私有成员)
  • 程序阶段
    • 源码阶段 --> 编译阶段 --> 【运行阶段


1. 构造方法(Constructor)
  • 可以用来创建对象、给成员变量赋值
  • Constructor getConstructor(Class…clazz) 获取被public修饰的构造方法对象。
  • Constructor[] getConstructors(); 获取所有被public修饰的构造方法对象。
  • Constructor getDeclaredConstructor(Class…clazz); 获取被任意权限修饰符修改的构造方法对象(包括private修饰的)。
  • Object newInstance(); 创建对象
2. 成员变量、静态变量 Field
  • 可以给成员变量赋值、取值
  • Field getField(String name); 获取被public修饰的指定的字段对象
  • Field[] getFields(); 获取被public修饰的指定的字段对象
  • Field getDeclaredField(String name); 获取被任意权限修饰符,修饰的指定的字段对象
  • set(Object obj,Object value); 给指定对象的field字段赋值。
  • get(Object obj); 获取指定对象field字段的值。
3. 成员方法、静态方法 Method
  • Method getMethod(String name,Class…clazz); 获取被public修饰的指定的方法对象
  • Method[] getMethods(); 获取被public修饰符,修饰的指定的方法对象
  • Method getDeclaredMethod(String name,Class…clazz); 获取被public修饰的指定的方法对象
  • Object invoke(Object obj,Object…obj); 调用方法,并返回结果

setAccessible(true)

  • 开启暴力反射,开启后才可以操作private修饰的成员,但这种方式破坏了Java的封装性原则,【不建议】使用
  • 注意:静态成员(变量、方法),同上面的操作基本相同,唯一不同的是,不需要传入对象,直接给null;
4. 获取字节码对象
  • Class clazz = Class.forName(“全类名”)
  • Class clazz = 类名.class
  • Class clazz = 对象名.getClass();
套路:
	1. 获取该类的字节码对象
	2. 获取构造方法对象,创建该类的对象
	3. 获取变量对象
	4. 获取方法对象

举个栗子

package com.st.Demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Student {
    public String name;
    private int age;
    public void saySomething(){}
    public Student(){}
    private 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;
    }
}

class Demo {
    public static void main(String[] arg) throws Exception {
        // 1. 获取该类的字节码对象
        Class<?> clazz = Class.forName("com.st.Demo.Student");

        // 2. 获取构造方法对象,创建该类的对象
        Constructor<?> cons = clazz.getConstructor();
        Object stu = cons.newInstance();

        // 3. 获取变量对象
        Field name = clazz.getField("name");

        // 4. 获取方法对象
        Method method = clazz.getMethod("saySomething");
        method.invoke(stu); //参数为调用 stu 的method(saySomething)方法
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值