JAVASEday17 反射

本文深入探讨了Java的反射机制,包括类加载过程、类加载器的分类和作用,以及如何通过反射获取构造方法、成员变量和成员方法。详细阐述了getConstructors、getDeclaredConstructors、getFields、getDeclaredFields、getMethod、getDeclaredMethod等关键方法的使用,展示了如何通过newInstance、set和invoke等方法动态操作对象。

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

类的加载

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

  • 加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
  • 连接:
    验证 : 是否有正确的内部结构,并和其他类协调一致
    准备 : 负责为类的静态成员分配内存,并设置默认初始化值
    解析: 把类中的符号引用转换为直接引用
  • 初始化:顺序,父类静态变量–> 父类静态代码块–> 子类静态变量–> 子类静态代码块 -->父类非静态变量–> 父类非静态代码块–> 父类构造函数–> 子类非静态变量–> 子类非静态代码块–> 子类构造函数

类加载器

类加载器的作用是负责将类加载进内存,并为之生成对应的class对象
分类:

  • Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
  • Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录
  • Sysetm ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

反射

java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性,这样动态获取类的信息一级动态调用对象的方法的功能称为java的反射机制。
想要剖析一个类,必须西安获取这个类的字节码对文件象,获取 字节码文件对象的方式有三种:

  • a: 第一种通过Object类中的getClass方法
  • b: 通过静态属性(class属性)
  • c: 通过Class类中的一个静态方法:
    -public static Class forName(String className):
    -className: 这个表示的是一个类对应的全类名(就是需要加上包名)
  //方式1. 通过Object类中的getClass方法
        Student student = new Student(); //Student.class
        //Class 类的实例表示正在运行的 Java 应用程序中的类和接口
        Class clazz = student.getClass();

        //方式2.任何一个类,都有一个 class属性,通过这个属性就可以获取到该类的字节码文件对象
        Class<Student> studentClass = Student.class;
        System.out.println(clazz==studentClass);
        //获取一个类的字节码文件对象的方式3
        //全路径:一个类带有包名  全类名:带有包名的类
        Class<?> aClass = Class.forName("org.westos.demo.Student");

通过反射获取构造方法

A:获取所有构造方法
public Constructor<?>[] getConstructors() 获取所有的构造方法不包含私有的
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法 包括私有的
B:获取单个构造方法
public Constructor getConstructor(Class<?>… parameterTypes) 获取单个的构造方法 不包含私有的
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) 获取单个的构造方法包含私有的
newInstance(Object… initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

public class Demo {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("day0802.Student");//拿到类的字节码文件对象
        //获取公共构造方法对象
        Constructor<?>[] constructors1 = aClass.getConstructors();
        for (Constructor<?> constructor : constructors1) {
            System.out.println(constructor);
        }
        System.out.println();
        //获取所有构造方法对象
        Constructor<?>[] constructors = aClass.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println();
        //空参构造
        Constructor<?> constructor = aClass.getConstructor();
        Object o = constructor.newInstance();
        //有参构造
        Constructor<?> constructor1 = aClass.getConstructor(String.class);
        Object 张三 = constructor1.newInstance("张三");

        Constructor<?> constructor2 = aClass.getConstructor(String.class, int.class);
        Object 李四 = constructor2.newInstance("李四", 23);
        //私有有参构造
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class);
        declaredConstructor.setAccessible(true);//取消权限检查
        Object o1 = declaredConstructor.newInstance(24);
        System.out.println(o==张三);
        
    }
}
class Student{
    public Student(){
        System.out.println("空参构造");
    }
    public Student(String name){
        System.out.println("有参构造"+name);
    }
    public Student(String name,int age){
        System.out.println("有参构造2"+name+age);
    }
    private Student(int age){
        System.out.println("私有有参构造");
    }
    public void show(){
        System.out.println("构造方法");
    }

}

通过反射获取成员变量

A:获取所有成员变量
public Field[] getFields() 获取所有的成员变量包含从父类继承过来的
public Field[] getDeclaredFields() 获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量
B:获取单个成员变量
public Field getField(String name) 获取单个公共字段对象
public Field getDeclaredField(String name) 获取单个私有字段对象

public class Student {
    public String name;
    public int age;
    private double money;
    public Student() {
    }
}
public class MyTest {
    public static void main(String[] args) throws NoSuchFieldException {
        //Field 字段类型
        Class<Student> studentClass = Student.class;
        //获取所有的公共字段对象
        Field[] fields = studentClass.getFields();
        for (Field field : fields) {
            System.out.println(field.toString());
        }
        System.out.println("----------------------");
        //获取所有的字段对象,包括私有的
        Field[] declaredFields = studentClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());
        }

        //获取单个公共字段对象
        Field name = studentClass.getField("name");
        System.out.println(name);

        //获取单个的私有字段对象
        Field money = studentClass.getDeclaredField("money");
        System.out.println(money);
    }
}

C: 给字段赋值

 public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("org.westos.demo4.Student");
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Object object= declaredConstructor.newInstance();

        //以前我们给字段赋值
        //Student student = new Student();
        //student.name="张三";
        Field name = aClass.getField("name");
        name.set(object,"张三");
        Object o = name.get(object);
        System.out.println(o);
    }

通过反射获取成员方法

A:获取所有成员方法
public Method[] getMethods() //获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法
public Method[] getDeclaredMethods()//获取自己的所有成员方法 包含私有的
B:获取单个成员方法
//参数1: 方法名称 参数2:方法行参的class 对象
public Method getMethod(String name,Class<?>… parameterTypes) //获取单个的方法 不包含私有的
public Method getDeclaredMethod(String name,Class<?>… parameterTypes) 获取单个方法包括私有的
invoke(Object obj, Object… args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

public class MyTest2 {
    public static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("org.westos.demo5.Student");
        Constructor<?> constructor = aClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        Student obj = (Student) constructor.newInstance();
       // obj.show();

        //获取方法对象
        Method show = aClass.getMethod("show");
        //通过反射的反射,来让方法执行invoke()让方法执行
        show.invoke(obj);
        System.out.println("---------------------");
        Method test = aClass.getMethod("test", String.class, int.class);
        //参1:该类的对象,参数2:传给方法的形参要的值
        test.invoke(obj,"zhangsan",23);

        Method hehe = aClass.getMethod("hehe", double.class);
        Object invoke = hehe.invoke(obj, 3.2);
        System.out.println(invoke);

        System.out.println("-----------------------------");
        //通过反射,掉私有的方法
        Method haha = aClass.getDeclaredMethod("haha");
        haha.setAccessible(true);//调用私有方法,取消权限检查
        Object invoke1 = haha.invoke(obj);
        System.out.println(invoke1);
    }
}
public class Student {
    private Student() {
    }

    public void show(){
        System.out.println("空参数的show方法执行了");
    }

    public void test(String name,int age) {
        System.out.println("两个参数的 test方法执行了"+name+"==="+age);
    }

    public String hehe(double num) {
        System.out.println("有返回值的方法执行了"+num);
        return "呵呵";
    }

    private String haha(){
        System.out.println("私有的方法执行了");
        return "哈哈";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值