Java的反射机制

一、Java的反射概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象


 

新建Class类进行测试:

 

package com.hansun.entity;

public class Person {
    public String name;
    public int age;

    public Person() {
    }

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

    public String show(){
        return "name:"+name+", age :"+age;
    }
}

 

package com.hansun.entity;

public class Student extends Person {

    public String className;

    private String address;

    public Student() {
        super();
    }

    private Student(String name, int age, String className) {
        super(name, age);
        this.className = className;
    }

    public Student(String name, int age, String className, String address) {
        super(name, age);
        this.className = className;
        this.address = address;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    private void add(int a, int b) {
        System.out.println(a + b);
    }

    @Override
    public String toString() {
        return "Student{" +
                "className='" + className + '\'' +
                ", address='" + address + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 

 

 

二、获取反射的方式

// 通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
1、Class clazz1 = Class.forName("全限定类名");

//当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
2、Class clazz2  = Person.class;

//通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
3、Class clazz3 = p.getClass();

 


验证三种方式获取的Class对象是否同一个

/**
 * 测试三种反射得来的Class对象  是否是同一个
 */
private static void testClass() throws ClassNotFoundException {
    // 第一种方式获取Class对象
    // new 产生一个Student对象,一个Class对象。
    Student stu1 = new Student();
    //获取Class对象
    Class stuClass = stu1.getClass();
    System.out.println(stuClass.getName());

    // 第二种方式获取Class对象
    Class stuClass2 = Student.class;
    // 判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
    System.out.println(stuClass == stuClass2);

    // 第三种方式获取Class对象
    // 注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
    Class stuClass3 = Class.forName("com.hansun.entity.Student");
    // 判断三种方式是否获取的是同一个Class对象
    System.out.println(stuClass3 == stuClass2);

}

 

 

 

三、获取类Class对象中成员变量Field字段

private static void testField() throws Exception {
    Class cls = Class.forName("com.hansun.entity.Student");
    //获取成员变量,包括子类及父类,同时只能包含公共的方法
    Field[] fields = cls.getFields();
    for (Field field : fields) {
        System.out.print(field + "\t");
        System.out.print(field.getModifiers() + "\t");
        System.out.print(field.getType() + "\t");
        System.out.print(field.getName() + "\t");
        System.out.println();
    }
    System.out.println("========================");


    //此方法返回的是当前类的所有属性,不仅仅局限于公共访问修饰符,所有的访问修饰符都可以拿到
    Field[] declaredFields = cls.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.print(declaredField + "\t");
        System.out.print(declaredField.getModifiers() + "\t");
        System.out.print(declaredField.getType() + "\t");
        System.out.println(declaredField.getName());
    }
    System.out.println("========================");


    // 反射在一定程度上破坏了封装性,需要合理使用
    Field address = cls.getDeclaredField("address");
    // 设置该属性是否能被访问,true表示能被访问,破坏了封装性
    address.setAccessible(true);

    System.out.println(address.getName());
    Object o = cls.newInstance();
    address.set(o, "北京市");
    System.out.println(((Student) o).getAddress());
    System.out.println("========================");
}

 

 

 

四、获取类Class对象中method方法

private static void testMethod() throws Exception {
    Class cls = Class.forName("com.hansun.entity.Student");

    // 获取该对象的普通方法,包含的方法范围是当前对象及父类对象的所有公共方法
    Method[] methods = cls.getMethods();
    for (Method method : methods) {
        System.out.print(method.getModifiers() + "\t");
        System.out.print(method.getName() + "\t");
        System.out.println(Arrays.toString(method.getParameterTypes()));
    }
    System.out.println("-----------------------");


    // 获取当前类中所有的方法,无论什么访问修饰符
    Method[] declaredMethods = cls.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.print(declaredMethod.getModifiers() + "\t");
        System.out.print(declaredMethod.getName() + "\t");
        System.out.println(Arrays.toString(declaredMethod.getParameterTypes()));

    }
    System.out.println("-----------------------");


    Method add = cls.getDeclaredMethod("add", int.class, int.class);
    cls.getDeclaredMethods();
    add.setAccessible(true);
    Object o1 = cls.newInstance();
    add.invoke(o1, 123, 87);

    Method setAddress = cls.getDeclaredMethod("setAddress", String.class);
    setAddress.invoke(o1, "上海市!");
    System.out.println(o1.toString());
}

 

 

 

 

 五、获取类Class对象中的Constructor构造器

private static void testConstructor() throws Exception {
    Class cls = Class.forName("com.hansun.entity.Student");

    // 获取对象的所有构造方法,只能获取公有的改造方法
    Constructor[] constructors = cls.getConstructors();
    for (Constructor constructor : constructors) {
        System.out.print(constructor.getModifiers() + "\t");
        System.out.println(constructor.getName());
    }
    System.out.println("========================");
    // 获取所有的构造方法,无论是私有还是公有
    Constructor[] declaredConstructors = cls.getDeclaredConstructors();
    for (Constructor declaredConstructor : declaredConstructors) {
        System.out.print(declaredConstructor.getModifiers() + "\t");
        System.out.print(declaredConstructor.getName() + "\t");
        // 获取构造器中方法签名
        System.out.print(Arrays.toString(declaredConstructor.getParameterTypes()) + "\t");
        System.out.println(declaredConstructor.getParameterCount() + "\t");
    }
    // 如何调用私有的构造方法呢?
    Constructor<Student> declaredConstructor = cls.getDeclaredConstructor(String.class, int.class, String.class);
    declaredConstructor.setAccessible(true);
    Student o2 = declaredConstructor.newInstance("sunhan", 23, "aaaaaaaaaaa");
    System.out.println(o2);
}

 

posted @ 2020-07-21 11:13  花碎梦亦寒  阅读(190)  评论(0编辑  收藏  举报