Java 反射


什么是反射?

反射是 Java 中一个非常重要的高级特性,基本上 Spring 等一系列框架都是基于反射的思想写成的。

什么是反射?

  1. 程序的运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法
  2. 对于任意一个对象,都能够调用它的任意属性和方法
  3. 这种动态获取类信息以及动态调用对象方法的功能称为 Java 语言的反射机制。

反射主要提供了以下功能:

  • 动态获取:动态获取类或对象的属性和方法
  • 动态调用:动态调用对象的属性和方法

这么一看,反射就像是一个掌控全局的角色,不管你程序怎么运行,我都能够知道你这个类有哪些属性和方法,你这个对象是由谁调用的。

image

image

实现方式:

image

为什么要有反射:

有的同学可能会疑惑,Java 已经有了封装为什么还要有反射呢?反射看起来像是破坏了封装性。甚至让私有变量都可以被外部访问到,使得类变得不那么安全了。

从 Oracle 官方文档中可以看出,反射主要应用在以下几方面:

  • 反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
  • 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码。
  • 测试时可以利用反射 API 访问类的私有成员,以保证测试代码覆盖率。

也就是说,Oracle 希望开发者将反射作为一个工具,用来帮助程序员实现本不可能实现的功能(perform operations which would otherwise be impossible)。

反射的使用场景:

  • 操作因访问权限限制的属性和方法
  • 实现自定义注解
  • 动态加载第三方 jar 包
  • 按需加载类,节省编译和初始化时间

获取 Class 类对象的三种方式

反射最重要的一个作用就是可以在运行时动态地创建类的对象,其中 Class 类是反射机制中最重要的类。

获取 Class 类对象的三种方式

  1. 类名.class 属性
  2. 对象名.getClass()
  3. Class.forName(全类名)

image

示例:

  • 学生类
package com.demo;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public 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;
    }

    public void study(){
        System.out.println("学生在学习");
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 测试类:获取学生类对象的三种方式
package com.example.demo;
import com.demo.Student;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式一:Class类中的静态方法forName("全类名")
        // 全类名:包名 + 类名
        Class clazz1 = Class.forName("com.demo.Student");
        System.out.println(clazz1);  // class com.demo.Student

        // 方式二:通过class属性来获取
        Class clazz2 = Student.class;
        System.out.println(clazz2);  // class com.demo.Student

        // 方式三:利用对象的getClass方法来获取class对象
        //getClass方法是定义在Object类中.
        Student s = new Student();
        Class clazz3 = s.getClass();
        System.out.println(clazz3);  // class com.demo.Student

        System.out.println(clazz1 == clazz2);  // true
        System.out.println(clazz2 == clazz3);  // true
    }
}

反射获取 Class 类的对象

image

1)反射获取构造方法对象

Class 类获取构造方法对象

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

示例:

package com.demo;

public class Student {

    private String name;
    private int age;

    // 私有的有参构造方法
    private Student(String name) {
        System.out.println("name的值为:" + name);
        System.out.println("private...Student...有参构造方法");
    }

    // 公共的无参构造方法
    public Student() {
        System.out.println("public...Student...无参构造方法");
    }

    // 公共的有参构造方法
    public Student(String name, int age) {
        System.out.println("name的值为:" + name + "age的值为:" + age);
        System.out.println("public...Student...有参构造方法");
    }
}
package com.example.demo;
import java.lang.reflect.Constructor;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
         method1();
         method2();
         method3();
         method4();
    }

    private static void method4() throws ClassNotFoundException, NoSuchMethodException {
        // Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象         
        // 获取Class对象
        Class clazz = Class.forName("com.demo.Student");
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        System.out.println(constructor);  // private com.demo.Student(java.lang.String)
    }

    private static void method3() throws ClassNotFoundException, NoSuchMethodException {
        // Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象         
        // 获取Class对象
        Class clazz = Class.forName("com.demo.Student");
        // 小括号中一定要跟构造方法的形参保持一致
        Constructor constructor1 = clazz.getConstructor();
        System.out.println(constructor1);  // public com.demo.Student()

        Constructor constructor2 = clazz.getConstructor(String.class, int.class);
        System.out.println(constructor2);  // public com.demo.Student(java.lang.String,int)

        // 因为Student类中,没有只有一个int的构造,所以这里会报错.
        // Constructor constructor3 = clazz.getConstructor(int.class);
        // System.out.println(constructor3);
    }

    private static void method2() throws ClassNotFoundException {
        // Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组         
        // 获取Class对象
        Class clazz = Class.forName("com.demo.Student");

        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
//            private com.demo.Student(java.lang.String)
//            public com.demo.Student()
//            public com.demo.Student(java.lang.String,int)
        }
    }

    private static void method1() throws ClassNotFoundException {
        // Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
        // 获取Class对象
        Class clazz = Class.forName("com.demo.Student");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
            // public com.demo.Student()
            // public com.demo.Student(java.lang.String,int)
        }
    }
}

Constructor 类创建对象

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

示例:

package com.example.demo;
import com.demo.Student;  // 与上个示例一致
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, 
            InvocationTargetException, InstantiationException {
         // T newInstance(Object... initargs):根据指定的构造方法创建对象
         method1();
         method2();
         method3();
         method4();

    }

    private static void method4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, 
            IllegalAccessException, InvocationTargetException {
        // 获取一个私有的构造方法并创建对象
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取一个私有化的构造方法
        Constructor constructor = clazz.getDeclaredConstructor(String.class);

        // 被private修饰的成员,不能直接使用的
        // 如果用反射强行获取并使用,则需要临时取消访问检查
        constructor.setAccessible(true);

        // 3.直接创建对象
        Student student = (Student) constructor.newInstance("zhangsan");

        System.out.println(student);
        /*
            name的值为:zhangsan
            private...Student...有参构造方法
            com.demo.Student@677327b6
         */
    }

    private static void method3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        // 简写格式
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.在Class类中有一个newInstance方法,可以利用空参直接创建一个对象
        Student student = (Student) clazz.newInstance();  // 这个方法现在已经过时了

        System.out.println(student);
        /*
            public...Student...无参构造方法
            com.demo.Student@1540e19d
         */
    }

    private static void method2() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, 
            IllegalAccessException, InvocationTargetException {
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取构造方法对象
        Constructor constructor = clazz.getConstructor();

        // 3.利用空参来创建Student的对象
        Student student = (Student) constructor.newInstance();

        System.out.println(student);
        /*
            public...Student...无参构造方法
            com.demo.Student@4554617c
         */
    }

    private static void method1() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, 
            IllegalAccessException, InvocationTargetException {
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取构造方法对象
        Constructor constructor = clazz.getConstructor(String.class, int.class);

        // 3.利用newInstance创建Student的对象
        Student student = (Student) constructor.newInstance("zhangsan", 23);

        System.out.println(student);
        /*
            name的值为:zhangsanage的值为:23
            public...Student...有参构造方法
            com.demo.Student@74a14482
         */
    }
}

2)反射获取成员变量

Class 类获取成员变量

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

示例:

package com.demo;


public class Student {

    public String name;
    public int age;
    public String gender;
    private int money = 300;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", money=" + money +
                '}';
    }
}
package com.example.demo;
import java.lang.reflect.Field;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        method1();
        method2();
        method3();
        method4();
    }

    private static void method4() throws ClassNotFoundException, NoSuchFieldException {
        // Field getDeclaredField(String name):返回单个成员变量对象
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取money成员变量
        Field field = clazz.getDeclaredField("money");
        
        // 3.打印一下
        System.out.println(field);  // private int com.demo.Student.money
    }

    private static void method3() throws ClassNotFoundException, NoSuchFieldException {
        // Field getField(String name):返回单个公共成员变量对象
        // 想要获取的成员变量必须是真实存在的
        // 且必须是public修饰的
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取name这个成员变量
        Field field = clazz.getField("name");  // public java.lang.String com.demo.Student.name
        // Field field = clazz.getField("money");  // 报错,因为money是私有的

        // 3.打印一下
        System.out.println(field);
    }

    private static void method2() throws ClassNotFoundException {
        // Field[] getDeclaredFields():返回所有成员变量对象的数组
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取所有的Field对象
        Field[] fields = clazz.getDeclaredFields();

        // 3.遍历
        for (Field field : fields) {
            System.out.println(field);
        }
        /*
        public java.lang.String com.demo.Student.name
        public int com.demo.Student.age
        public java.lang.String com.demo.Student.gender
        private int com.demo.Student.money
         */
    }

    private static void method1() throws ClassNotFoundException {
        // Field[] getFields():返回所有公共成员变量对象的数组

        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取Field对象
        Field[] fields = clazz.getFields();

        // 3.遍历
        for (Field field : fields) {
            System.out.println(field);
        }
        /*
        public java.lang.String com.demo.Student.name
        public int com.demo.Student.age
        public java.lang.String com.demo.Student.gender
         */
    }
}

Field 类给成员变量赋值

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

示例:

package com.example.demo;
import com.demo.Student;
import java.lang.reflect.Field;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException,
            InstantiationException {
        method1();
        method2();
    }

    private static void method2() throws ClassNotFoundException, NoSuchFieldException, InstantiationException,
            IllegalAccessException {
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        // 2.获取成员变量Field的对象
        Field field = clazz.getDeclaredField("money");

        // 3.取消一下访问检查
        field.setAccessible(true);

        // 4.调用get方法来获取值
        // 4.1 创建一个对象
        Student student = (Student) clazz.newInstance();
        // 4.2 获取指定对象的money的值
        Object o = field.get(student);

        System.out.println(o);  // 300
    }

    private static void method1() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        // void set(Object obj, Object value):给obj对象的成员变量赋值为value
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");

        //2.获取name这个Field对象
        Field field = clazz.getField("name");

        // 3.利用set方法进行赋值
        // 3.1 先创建一个Student对象
        Student student = (Student) clazz.newInstance();
        // 3.2 有了对象才可以给指定对象进行赋值
        field.set(student, "zhangsan");

        System.out.println(student);  // Student{name='zhangsan', age=0, gender='null', money=300}
    }
}

3)反射获取成员方法

Class 类获取成员方法

方法名 说明
Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes) 返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象

示例:

package com.demo;

public class Student {

    // 私有的,无参无返回值
    private void show() {
        System.out.println("私有的show方法,无参无返回值");
    }

    // 公共的,无参无返回值
    public void function1() {
        System.out.println("function1方法,无参无返回值");
    }

    // 公共的,有参无返回值
    public void function2(String name) {
        System.out.println("function2方法,有参无返回值,参数为" + name);
    }

    // 公共的,无参有返回值
    public String function3() {
        System.out.println("function3方法,无参有返回值");
        return "aaa";
    }

    // 公共的,有参有返回值
    public String function4(String name) {
        System.out.println("function4方法,有参有返回值,参数为" + name);
        return "aaa";
    }
}
package com.example.demo;
import java.lang.reflect.Method;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        method1();
        method2();
        method3();
        method4();
        method5();
    }

    private static void method5() throws ClassNotFoundException, NoSuchMethodException {
        // Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");
        // 2.获取一个成员方法show
        Method method = clazz.getDeclaredMethod("show");
        
        System.out.println(method);  // private void com.demo.Student.show()
    }

    private static void method4() throws ClassNotFoundException, NoSuchMethodException {
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");
        // 2.获取一个有形参的方法function2
        Method method = clazz.getMethod("function2", String.class);
       
        System.out.println(method);  // public void com.demo.Student.function2(java.lang.String)
    }

    private static void method3() throws ClassNotFoundException, NoSuchMethodException {
        // Method getMethod(String name, Class<?>... parameterTypes):返回单个公共成员方法对象
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");
        // 2.获取成员方法function1
        Method method1 = clazz.getMethod("function1");
        
        System.out.println(method1);  // public void com.demo.Student.function1()
    }

    private static void method2() throws ClassNotFoundException {
        // Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");
        // 2.获取Method对象
        Method[] methods = clazz.getDeclaredMethods();
        // 3.遍历一下数组
        for (Method method : methods) {
            System.out.println(method);
        }
        /*
        public java.lang.String com.demo.Student.function3()
        public java.lang.String com.demo.Student.function4(java.lang.String)
        private void com.demo.Student.show()
        public void com.demo.Student.function2(java.lang.String)
        public void com.demo.Student.function1()
         */
    }

    private static void method1() throws ClassNotFoundException {
        // Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");
        // 2.获取成员方法对象
        Method[] methods = clazz.getMethods();
        // 3.遍历
        for (Method method : methods) {
            System.out.println(method);
        }
        /*
        public void com.demo.Student.function2(java.lang.String)
        public void com.demo.Student.function1()
        public final void java.lang.Object.wait() throws java.lang.InterruptedException
        public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
        public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
        public boolean java.lang.Object.equals(java.lang.Object)
        public java.lang.String java.lang.Object.toString()
        public native int java.lang.Object.hashCode()
        public final native java.lang.Class java.lang.Object.getClass()
        public final native void java.lang.Object.notify()
        public final native void java.lang.Object.notifyAll()
         */
    }
}

Method 类执行方法

方法名 说明
Object invoke(Object obj, Object... args) 运行方法
  • 参数一: 用 obj 对象调用该方法。
  • 参数二: 调用方法的传递的参数(如果没有就不写)。
  • 返回值: 方法的返回值(如果没有就不写)。

示例:

package com.example.demo;
import com.demo.Student;  // 与上个示例一致
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
        InstantiationException, InvocationTargetException {

        // 1.获取class对象
        Class clazz = Class.forName("com.demo.Student");
        // 2.获取里面的Method对象  function4
        Method method = clazz.getMethod("function4", String.class);
        // 3.运行function4方法
        // 3.1 创建一个Student对象,当做方法的调用者
        Student student = (Student) clazz.newInstance();
        // 3.2 运行方法
        Object result = method.invoke(student, "zhangsan");

        System.out.println(result);  
        /*
            function4方法,有参有返回值,参数为zhangsan
            aaa
         */
    }
}
posted @ 2021-10-04 14:55  Juno3550  阅读(83)  评论(0编辑  收藏  举报