目录

一、认识反射

1、反射的概念

2、反射的作用

3、反射相关的类

二、反射的使用

1、Class类

2、调用类中的私有构造方法

3、使用类中的私有成员变量

4、调用类中的私有成员方法 

三、反射的优点和缺点

1、优点

2、缺点


一、认识反射

1、反射的概念

        Java的反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法;对于任意一个对象,都能够调用它的任何方法和属性。这种动态获取类的信息以及动态调用方法的功能称为Java语言的反射(reflection)机制。

2、反射的作用

        Java程序中一些对象在运行时会出现两种类型:运行时类型编译时类型,例如一个向上转型的代码:Bird bird = new Animal();其中,bird在编译时类型为Bird,运行时类型为Animal,通过反射机制就能在程序运行时发现该对象和类的真实信息。

3、反射相关的类

Class类代表类的实体,在运行的Java应用程序中表示类和接口
Field类代表类的成员变量/字段
Method类代表类的方法
Constructor类代表类的构造方法

二、反射的使用

1、Class类

        在反射之前,我们需要先拿到当前需要反射的类的Class对象,然后通过Class对象调用相关的方法,来达到反射的目的。

获得Class对象的三种方式:

(1)使用Class.forName方法("类的全路径名");

(2)使用需要反射的类名调用class方法;

(3)使用需要反射的类的对象调用getClass方法

但是通过三种方式获取的Class对象都是相同的,也就是说,一个类只有一个对应的Class对象

Class类中常用获得类相关的方法
方法作用
getClassLoader()获得类的加载器
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String classRoad)根据类的路径返回类的Class对象(该方法是静态成员方法)
newInstacne()创建类的实例
getName()获得类的完整路径名

2、调用类中的私有构造方法

获得类中构造器相关的方法(返回值为Constructor类型相关)

方法作用
getConstructor(Class...<?>parameterTypes)获得该类中与参数类型匹配的公有的构造方法
getConstructors()获得该类中所有公有的构造方法
getDeclaredConstructor(Class...<?>parameterTypes)获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()获得该类中所有构造方法

示例: 

创建一个Student类:

public class Student {
    public String name;//公共的成员变量

    private int id = 1;//私有的成员变量

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

    private Student(int id){
        this.id = id;
        System.out.println("私有的构造方法");
    }

    public void func(){
        System.out.println("公共的成员方法");
    }

    private void func2(String s){
        System.out.println(s);
    }

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

在同一个包中的Test类中通过Student类私有的构造方法创建一个Student对象:

public class Test {
    public static void reflectPrivateConstructor(){
        try {
            //获得Class对象
            Class<?> c1 = Class.forName("reflect.Student");
            //调用getDeclaredField(String name)方法
            Constructor<?> constructor = c1.getDeclaredConstructor(int.class);
            //调用setAccessible(boolean)后可修改访问权限
            constructor.setAccessible(true);
            //通过Constructor对象创建Student对象
            Student student = (Student) constructor.newInstance(100);
            //输出创建好的Student对象
            System.out.println(student);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws ClassNotFoundException {
        reflectPrivateConstructor();
    }
}

代码运行结果:

 

3、使用类中的私有成员变量

获得类中字段相关的方法(返回值为Field类型相关)

方法作用
getField(String name)获得该类中某个公有的字段
getFields()获得该类中所有公有的字段
getDeclaredField(String name)获得该类中某个字段
getDeclaredFields()获得该类中所有字段

示例: 

反射Student类中的私有成员变量

public class Test {
    public static void reflectPrivateField(){
        try {
            //获得Class对象
            Class<?> c1 = Class.forName("reflect.Student");
            //getDeclaredField(String name)方法
            Field field = c1.getDeclaredField("id");
            //调用setAccessible(boolean)后可修改访问权限
            field.setAccessible(true);
            //通过Class类反射一个Student对象
            Student student = (Student) c1.newInstance();
            //修改指定Student对象的静态成员变量:id = 500
            field.set(student,500);
            //输出Student对象
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        reflectPrivateField();
    }
}

代码运行结果:

4、调用类中的私有成员方法 

获得类中方法相关的方法(返回值为Method类型相关)

方法作用
getMethod(String name,Class...<?>parameterTypes)获得该类中某个公有的方法
getMethods()获得该类中所有公有的方法
getDeclaredMethod(String name,Class...<?>parameterTypes)获得该类中某个方法
getDeclaredMethods()获得该类中所有方法

 示例: 

反射Student类中的私有成员方法

public class Test {
    public static void reflectPrivateMethod(){
        try {
            //获得Class对象
            Class<?> c1 = Class.forName("reflect.Student");
            //调用getDeclaredMethod(String name,Class...<?>parameterTypes)方法
            Method method = c1.getDeclaredMethod("func2",String.class);
            //获取私有的属性或方法一般都要调用setAccessible(boolean)方法
            method.setAccessible(true);
            //通过Class类反射一个Student对象
            Student student = (Student) c1.newInstance();
            //Method对象调用invoke方法
            //让指定的Student对象调用指定的私有方法并传参
            method.invoke(student,"通过反射机制调用Student类的私有方法");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        reflectPrivateMethod();
    }
}

代码运行结果:

三、反射的优点和缺点

1、优点

(1)对于任意一个类,都能够获得这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;

(2)增加程序的灵活性和扩展性,降低耦合性。

2、缺点

(1)使用反射会导致程序效率降低(为了获得一个类的对象,调用了Class类中的多个方法);

(2)反射机制绕过了源代码,可能会带来维护问题。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐