反射1

7 阅读4分钟

反射

反射允许对成员变量、成员方法和构造方法的信息进行编程访问。简单来说就是获取类里所有的信息。IDEA里自动提示的功能就是通过反射实现的。

获取class对象的三种方式

1.Class.forName("全类名")

2.类名.class

3.对象.getclass()

这三种方式对应Java当中三个不同的阶段。如果我们想创建一个类对象,分为以下三个阶段:

1.编写.java文件,并将其编译为.class字节码文件。在这个阶段代码没有被加载到内存中,只是在硬盘上进行操作。这个阶段是源代码阶段。源代码阶段使用第一种方式获取class对象

2.接下来要运行代码。将.class字节码文件加载到内存当中。这个阶段是加载阶段。加载阶段使用第二种方式

3.我们可以在内存中new一个对象,这个阶段是运行阶段。运行阶段使用第三种方式。

public class ReflectionDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.第一种方式
        //全类名:包名+类名,选中类名,右键找到复制/粘贴特殊,点击复制引用
        //最为常用
        Class Clazz1 = Class.forName("learn.reflection.Student");
​
        //打印
        System.out.println(Clazz1);
​
        //2.第二种方式,一般更多的是当作参数进行传递
        Class Clazz2 = Student.class;
​
        //验证
        System.out.println(Clazz1 == Clazz2);
​
        //3.第三种方式
        //当我们已经有了这个类的对象时才能使用
        Student stu = new Student();
        Class Clazz3 = stu.getClass();
​
        //验证
        System.out.println(Clazz1 == Clazz2);
        System.out.println(Clazz2 == Clazz3);
    }
}

利用反射获取构造方法

Class类中用于获取构造方法的方法:

方法名称说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Constructor<T>getConstructor(Class<?>...parameterTypes)返回单个公共构造方法对象
Constructor<T>getDeclaredConstructor(Class<?>...parameterTypes)返回单个构造方法对象

Constructor类中用于创建对象的方法

方法名称说明
T newInstance(Object...initargs)根据指定的构造方法创建对象
setAccessible(boolean flag)设置为true,表示取消访问检查

新增几个构造函数:

public class Student {
    private String name;
    private int age;
​
    public Student() {
    }
​
    public Student(String name) {
        this.name = name;
    }
​
    protected Student(int age) {
        this.age = age;
    }
​
    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;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}
public class ReflectionDemo1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取Student类的class字节码文件对象
        Class clazz = Class.forName("learn.reflection.Student");
​
        //2.获取public构造方法
        Constructor[] cons = clazz.getConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }
​
        System.out.println("-------------");
​
        //3.获取所有构造方法
        Constructor[] dc = clazz.getDeclaredConstructors();
        for (Constructor con : dc) {
            System.out.println(con);
        }
​
        System.out.println("-------------");
​
        //获取单个构造方法:空参构造
        System.out.println(clazz.getDeclaredConstructor());
​
        //获取单个构造方法:参数为一个String类型变量的构造函数
        //括号中的参数与想要获得的构造方法的参数对应
        System.out.println(clazz.getDeclaredConstructor(String.class));
​
        //获取单个构造方法:参数为一个String类型和一个int类型变量的构造函数
        Constructor TempCon = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println(TempCon);
​
        System.out.println("-------------");
​
        //获取权限修饰符:.getModifiers方法
        //public为1,private为2,protected为4
        //static为8,final为16,synchronized为32
        //用的都是2的n次幂
        System.out.println(TempCon.getModifiers());
​
        System.out.println("-------------");
​
        //获取参数
        Parameter[] parameters = TempCon.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
​
        System.out.println("-------------");
​
        //通过反射创建对象
        //由于两个参数的构造方法为priavte
        //要先临时取消权限校验
        TempCon.setAccessible(true);
        Student stu = (Student) TempCon.newInstance("张三",18);
        System.out.println(stu);
    }
}

利用反射获取成员变量

Class类中用于获取成员变量的方法

方法名称说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象

Field类中用于创建对象的方法

方法名称说明
void set(Object obj, Object value)赋值
Object get(Object obj)获取值

修改Student类的内容:

public class Student {
    private String name;
    private int age;
    public String gender;
​
    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
​
    public Student() {
    }
​
    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 String getGender() {
        return gender;
    }
​
    public void setGender(String gender) {
        this.gender = gender;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", gender='" + gender + ''' +
                '}';
    }
}
public class ReflectionDemo1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.获取Student类的class字节码文件对象
        Class clazz = Class.forName("learn.reflection.Student");
​
        //2.获取public成员变量
        Field[] fields1 = clazz.getFields();
​
        for (Field field : fields1) {
            System.out.println(field);
        }
​
        System.out.println("-------------");
​
        //3.获取所有成员变量
        Field[] fields2 = clazz.getDeclaredFields();
​
        for (Field field : fields2) {
            System.out.println(field);
        }
​
        System.out.println("-------------");
​
        //4.获取单个的成员变量
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);
​
        System.out.println("-------------");
​
        //5.获取权限修饰符
        System.out.println(name.getModifiers());
​
        System.out.println("-------------");
​
        //6.获取成员变量名
        System.out.println(name.getName());
​
        System.out.println("-------------");
​
        //7.获取成员变量类型
        System.out.println(name.getType());
​
        System.out.println("-------------");
​
        //8.获取成员变量记录的值
        Student s = new Student("张三",18,"男");
        name.setAccessible(true);
        Object value = name.get(s);
        System.out.println(value);
​
        System.out.println("-------------");
​
        //9.修改对象记录的值
        name.set(s,"凯文");
        System.out.println(s);
    }
}

利用反射获取成员方法

方法名与前面类似,改成Method而已。

有几点需要注意:

1.getMethods方法可以获取所有public的方法对象,包括父类中所有的public方法。getDeclaredMethods则不能获取父类的,但可以获取私有的(和前面一样)

2.获取方法抛出的异常:

        Class[] exceptionTypes = m.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

3.方法运行

        Student s = new Student();
        clazz.getMethod("eat", String.class).invoke(s,"汉堡");

invoke第一个参数表示方法的调用者,第二个参数表示在调用方法的时候传递的实际参数