java的反射

一. 反射的由来

vip

 

编译阶段:将java文件编译成字节码文件。

加载过程:通过类加载器,在方法区中加载类的静态属性和静态方法,在堆中存放该类的反射类对象。

运行过程:执行方法。

二. 反射的用法

首先创建Dog类

复制代码
public class Dog {
    public String name;
    public int age;
    public String color;

    public Dog(){}

    public Dog(String name, Integer age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public void run(){
        System.out.println(name + "在跑步");
    }

    public void sleep(){
        System.out.println(name + "在睡觉");
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}
复制代码

反射对象的方法使用

复制代码
public class Reflection03 {
    public static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("com.hspedu.Dog");
        // class com.hspedu.Dog  aClass引用指向的是Dog类的Class【反射对象】
        System.out.println(aClass);
        // class java.lang.Class aClass对象的运行类型Class【反射类】
        System.out.println(aClass.getClass());
        // 1.获取类的路径
        String name = aClass.getName();
        System.out.println(name);
        // 2.获取包名
        Package aPackage = aClass.getPackage();
        System.out.println(aPackage);
        // 3.1 获取无参构造器
        // public com.hspedu.Dog()
        Constructor<?> constructor1 = aClass.getConstructor();
        System.out.println(constructor1);
        // 3.2 获取带参构造器
        // public com.hspedu.Dog(java.lang.String,java.lang.Integer,java.lang.String)
        Constructor<?> constructor2 = aClass.getConstructor(String.class, Integer.class, String.class);
        System.out.println(constructor2);
        // 4 获取对象【无参】
        Object o = aClass.newInstance();
        // com.hspedu.Dog
        System.out.println(o.getClass());
        // 5.设置属性
        Field dogName = aClass.getField("name");
        dogName.set(o,"Tom");
        Field age = aClass.getField("age");
        age.set(o,8);
        Field color = aClass.getField("color");
        color.set(o,"白色");
        System.out.println(o);
        // 6.调用方法
        Method run = aClass.getMethod("run");
        run.invoke(o);
        Method sleep = aClass.getMethod("sleep");
        sleep.invoke(o);
        // 7.一次性得到反射对象的属性
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }


    }
}
复制代码

三. 获取反射对象

复制代码
public class Reflection04 {
    public static void main(String[] args) throws Exception{
        // 获取反射对象
        // 方式1:编译阶段,通过Class.forName(类的路径)
        Class<?> aClass = Class.forName("com.hspedu.Dog");
        System.out.println(aClass.hashCode());
        // 方式2:加载阶段,类名.class
        Class<Dog> dogClass = Dog.class;
        System.out.println(dogClass.hashCode());
        // 方式3:类加载器
        Class<?> aClass1 = ClassLoader.getSystemClassLoader().loadClass("com.hspedu.Dog");
        System.out.println(aClass1.hashCode());
        // 方式4:基本数据类型.class
        Class<Integer> integerClass = int.class;
        System.out.println(integerClass.hashCode());
        // 方式5:包装类.TYPE
        Class<Integer> type = Integer.TYPE;
        System.out.println(type.hashCode());

    }
}
复制代码

运行结果:

1554874502
1554874502
1554874502
1846274136
1846274136

说明同一个类的反射对象只有一个。

 四. 类加载解读

1. 静态加载和动态加载

加载包括:静态加载和动态加载
静态加载:在编译阶段,加载所有的类,遇到没有import导入的类,编译异常;
动态加载:在运行阶段,加载所需要的类,如果没有,不出现编译异常,但是肯定有运行异常。
动态加载:反射【五种方式】;
静态加载:new ;调用静态成员;子类被加载时,父类也被加载。

2. 类加载的具体过程

类加载图解:

vip

这里的初始化,是静态成员的初始化,静态成员随着类的加载而加载。

类加载三个阶段的主要任务:

vip

 五.综合案例,获取类的结构信息

复制代码
public class Reflection06 {
    public static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("com.hspedu.Student");
        // 1.获取本类及其父类的public修饰的属性
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println("本类及其父类的public修饰的属性: " + field.getName());
        }
        // 2.获取父类的public修饰的属性
        Class<?> superclass3 = aClass.getSuperclass();
        Field[] fields1 = superclass3.getFields();
        for (Field field : fields1) {
            System.out.println("父类的public修饰的属性: "+field.getName());
        }
        // 3.获取本类中的所有属性
        Field[] declaredFields1 = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields1) {
            System.out.println("本类的所有属性: " + declaredField.getName());
        }
        // 4.获取父类的所有属性
        Class<?> superclass = aClass.getSuperclass();
        Field[] declaredFields2 = superclass.getDeclaredFields();
        for (Field field : declaredFields2) {
            System.out.println("父类的所有属性: " + field.getName());
        }

        // 5.获取本类以及父类的public修饰的方法
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            System.out.println("本类以及父类的public修饰的方法: " + method.getName());
        }

        // 6.获取父类的public修饰的方法
        Class<?> superclass1 = aClass.getSuperclass();
        Method[] methods1 = superclass1.getMethods();
        for (Method method : methods1) {
            System.out.println("父类的public修饰的方法: " + method.getName());
        }

        // 7.获取本类的所有方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类的所有方法: " + declaredMethod.getName());
        }

        // 8.获取父类的所有方法
        Class<?> superclass2 = aClass.getSuperclass();
        Method[] declaredMethods1 = superclass1.getDeclaredMethods();
        for (Method method : declaredMethods1) {
            System.out.println("父类的所有方法: " + method.getName());
        }

        // 9.获取本类的public修饰的无参构造器
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("本类的public修饰的无参构造器: " + constructor.getName());
        }
        // 获取本类指定的带参构造器
        Constructor<?> constructor1 = aClass.getConstructor(String.class, String.class);
        System.out.println(constructor1);

        // 10.获取父类的public修饰的无参构造器
        Class<?> superclass4 = aClass.getSuperclass();
        Constructor<?>[] constructors1 = superclass4.getConstructors();
        for (Constructor<?> constructor : constructors1) {
            System.out.println("父类的public修饰的无参构造器: " + constructor.getName());
        }
        // 获取父类指定的带参构造器
        Constructor<?> constructor = superclass4.getConstructor(String.class, int.class);
        System.out.println(constructor);

        // 11.获取本类所有的构造器
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        // 12.获取父类的所有构造器
        Class<?> superclass5 = aClass.getSuperclass();
        Constructor<?>[] declaredConstructors1 = superclass5.getDeclaredConstructors();
        for (Constructor<?> constructor2 : declaredConstructors1) {
            System.out.println(constructor2);
        }

        // 13.获取本类的实现的接口
        Class<?>[] interfaces = aClass.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println(anInterface);
        }
    }
}

interface i1 {

}

interface i2 {

}

class Person {
    private String name;
    int age;
    protected String nation;
    public String gender;

    public Person() {}
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    private Person(String name, String nation) {
        this.name = name;
        this.nation = nation;
    }

    public void p1(){

    }
    protected void p2(){

    }
    void p3(){

    }
    private void p4(){

    }

}

class Student extends Person implements i1,i2{
    private String stuId;
    String hobby;
    protected String job;
    public int height;

    public Student(){}
    public Student(String stuId,String hobby){
        this.stuId = stuId;
        this.hobby = hobby;
    }
    private Student(String stuId,int height){
        this.height = height;
        this.stuId = stuId;
    }

    public void s1(){

    }
    protected void s2(){

    }
    void s3(){

    }
    private void s4(){

    }
}
复制代码

 运行结果:

复制代码
本类及其父类的public修饰的属性: height
本类及其父类的public修饰的属性: gender
父类的public修饰的属性: gender
本类的所有属性: stuId
本类的所有属性: hobby
本类的所有属性: job
本类的所有属性: height
父类的所有属性: name
父类的所有属性: age
父类的所有属性: nation
父类的所有属性: gender
本类以及父类的public修饰的方法: s1
本类以及父类的public修饰的方法: p1
本类以及父类的public修饰的方法: wait
本类以及父类的public修饰的方法: wait
本类以及父类的public修饰的方法: wait
本类以及父类的public修饰的方法: equals
本类以及父类的public修饰的方法: toString
本类以及父类的public修饰的方法: hashCode
本类以及父类的public修饰的方法: getClass
本类以及父类的public修饰的方法: notify
本类以及父类的public修饰的方法: notifyAll
父类的public修饰的方法: p1
父类的public修饰的方法: wait
父类的public修饰的方法: wait
父类的public修饰的方法: wait
父类的public修饰的方法: equals
父类的public修饰的方法: toString
父类的public修饰的方法: hashCode
父类的public修饰的方法: getClass
父类的public修饰的方法: notify
父类的public修饰的方法: notifyAll
本类的所有方法: s4
本类的所有方法: s3
本类的所有方法: s1
本类的所有方法: s2
父类的所有方法: p4
父类的所有方法: p3
父类的所有方法: p1
父类的所有方法: p2
本类的public修饰的无参构造器: com.hspedu.Student
本类的public修饰的无参构造器: com.hspedu.Student
public com.hspedu.Student(java.lang.String,java.lang.String)
父类的public修饰的无参构造器: com.hspedu.Person
父类的public修饰的无参构造器: com.hspedu.Person
public com.hspedu.Person(java.lang.String,int)
private com.hspedu.Student(java.lang.String,int)
public com.hspedu.Student(java.lang.String,java.lang.String)
public com.hspedu.Student()
private com.hspedu.Person(java.lang.String,java.lang.String)
public com.hspedu.Person(java.lang.String,int)
public com.hspedu.Person()
interface com.hspedu.i1
interface com.hspedu.i2
View Code
复制代码

 六.通过反射对象,创建实例

复制代码
public class Reflection07 {
    public static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("com.hspedu.AA");
        // 通过反射对象,创建实例
        // 方式1:
        Object a1 = aClass.newInstance();
        System.out.println(a1);
        // 方式2:
        Constructor<?> constructor = aClass.getConstructor();
        Object a2 = constructor.newInstance();
        System.out.println(a2);
        // 方式3:
        Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class);
        Object a3 = constructor1.newInstance("jack", 20);
        System.out.println(a3);
        // 方式4:
        // getConstructor()只能访问public属性的构造器
        // getDeclaredConstructor()可以访问私有的构造器
        Constructor<?> constructor2 = aClass.getDeclaredConstructor(String.class);
        // 爆破,可以访问private的构造器/属性/方法
        constructor2.setAccessible(true);
        Object a4 = constructor2.newInstance("white");
        System.out.println(a4);

        // 使用爆破,调用私有属性和方法
        // getField() 访问public修饰的属性
        // getDeclaredField() 可以访问private修饰的属性
        Field name = aClass.getDeclaredField("name");
        Field height = aClass.getField("height");
        System.out.println("a4的height: " + height.get(a4));
        // 使用属性.set修改public修饰的属性的值
        height.set(a4,180.00);

        // 修改私有属性的值
        // 方式1: 利用爆破,访问私有属性,修改private属性的值
        name.setAccessible(true);
        name.set(a4,"jhon");
        // 方式2: 通过反射调用public修饰的set()方法,修改private属性的值
        Method setName = aClass.getMethod("setName", String.class);
        setName.invoke(a4,"zwGitOne");
        System.out.println(a4);

        // 访问私有方法
        // getMethod() 访问public修饰的方法
        // getDeclaredMethod() 可以访问private修饰的方法
        Method run = aClass.getDeclaredMethod("run");
        run.setAccessible(true);
        run.invoke(a4);

    }
}

class AA {
    private String name = "tom";
    int age = 10;
    protected String gender = "男";
    public double height = 100.0;

    public void setName(String name) {
        this.name = name;
    }

    public AA(){}
    public AA(String name,int age){
        this.name = name;
        this.age = age;
    }

    private AA(String name){
        this.name = name;
    }

    private void run(){
        System.out.println(name + " is running");
    }

    @Override
    public String toString() {
        return "AA{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", height=" + height +
                '}';
    }
}
复制代码

运行结果:

AA{name='tom', age=10, gender='男', height=100.0}
AA{name='tom', age=10, gender='男', height=100.0}
AA{name='jack', age=20, gender='男', height=100.0}
AA{name='white', age=10, gender='男', height=100.0}
a4的height: 100.0
AA{name='zwGitOne', age=10, gender='男', height=180.0}
zwGitOne is running

总结:

// getField() 访问public修饰的属性
// getDeclaredField() 可以访问private修饰的属性
// getMethod() 访问public修饰的方法
// getDeclaredMethod() 可以访问private修饰的方法
// getConstructor()只能访问public属性的构造器
// getDeclaredConstructor()可以访问私有的构造器

declared,可以得到所有的属性/方法/构造器【但是不能对其进行修改,传参操作】,如果没有declared,则只能访问public修饰的属性/方法/构造器。

如果想要修改,传参,则必须 private属性.setAccessible(true)【爆破】,此时便能访问到属性/方法/构造器,自然能够进行修改和传参操作。

复制代码
// 爆破私有构造器
constructor2.setAccessible(true);
Object a4 = constructor2.newInstance("white");
// 爆破私有属性
name.setAccessible(true);
name.set(a4,"jhon");
// 爆破私有方法
Method run = aClass.getDeclaredMethod("run");
run.setAccessible(true);
run.invoke(a4);
复制代码

 

posted @   zwGitOne  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示