Java中的反射

一,什么是反射

在Java中,反射是指在运行时动态地获取和使用类的信息的能力。反射允许程序在运行时检查类、接口、字段和方法,以及动态实例化对象、调用方法和访问或修改字段的属性。简单来说,对于任意一个类,通过反射就可以知道这个类的所有属性和方法,并且可以通过反射进行调用。

二,反射相关的类

类名 用途
Class类 代表类的实体,表示类和接口
Field类 代表类的属性
Method类 代表类的方法
Constructor类 代表类的构造方法

三,获取Class对象的三种方式

方法 用途
getClassLoader() 获得类的加载器
getDeclaredClasses() 返回一个数组,数组中包含该类的所有类和接口类的对象
forName(String className) 根据类名返回类的对象
newInstance() 创建类的实例
getName() 获得类的完整路径名,例如 Student.class.getName()

在反射之前,我们要获得需要反射的类的Class对象,然后通过Class对象的方法,达到反射的目的,例如我们要获取Student类的对象:

class Student{
    private String name = "zhangsan";
    public int age = 18;
    public Student(){
        System.out.println("无参数构造方法");
    }

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

    private void set(String name, int age){
        System.out.println(name + " " + age);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. 使用Class.forName("类的全路径名")
  2. 使用 .class 方法
  3. 使用类对象的  getClass()方法
public class Test {
    // Student类的 Class类对象 只有一个,a,b,c的值相同
    public static void main(String[] args) {

        //1
        Class a;
        try {
            a = Class.forName("Student");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

        //2
        Class b;
        b = Student.class;

        //3
        Student student = new Student();
        Class c = student.getClass();
    }
}

四,反射的使用

4.1 新建一个student类对象

上面提到的三种方法只是得到了Student类的class类对象,不是得到Student类的实例化对象,我们要通过得到的Student类的class类对象来实例化一个Student对象。例如:

public class Demo1 {
    public static void reflectCreateClass(){
        Class a;
        try {

            a = Class.forName("Student");
            //newInstance()是创建一个a的实例,返回的类型是Object
            //所以要向下转型
            Student student = (Student) a.newInstance();
            
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

4.2 反射构造方法

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

注:getConstructor()方法的括号中填写我们需要反射的构造方法参数类型的class类对象,举一个反射私有构造方法的例子,这里的Student类和上文中的一样:

    public static void reflectPrivateConstrutor(){
        Class a;
        try {
            a = Class.forName("Student");

            //使用反射得到私有构造方法
            Constructor constructor =
                    (Constructor) a.getDeclaredConstructor(String.class, int.class);
            //私有方法不能在类外使用,要想调用,我们要给予权限,也就是下面的代码
            constructor.setAccessible(true);
            //调用私有的构造方法并传参
            Student student1 = constructor.newInstance("ll",20);
            
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

4.3 反射类的属性

方法 用途
getField(String name) 获得类对象的某个公有属性
getFields() 获得类对象的全部公有属性
getDeclaredField(String name) 获得类对象的属性(主要用来获得私有)
getDeclaredFields() 获得类对象的全部属性(主要用来获得私有)

举一个反射类的私有属性的例子,这里的Student类和上文中的一样:

public class Demo1 {
    //私有属性
    private static void reflectPrivateField(){
        Class a;
        try {
            a = Class.forName("Student");
            Field field = a.getDeclaredField("name");//获得name的属性
            field.setAccessible(true);//因为私有...
            Student student = (Student) a.newInstance();//实例化对象

            field.set(student,"wangwu");//将student对象的name改成wangwu
            System.out.println(student);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

4.4 反射类的方法

方法 用途
getMethod(String name,Class... parmeterTypes) 获得该类公有方法
getMethods() 获得该类所有公有方法
getDeclaredMethod(String name,Class... parmeterTypes) 获得该类方法
getDeclaredMethods() 获得该类所有方法

举一个反射类的私有方法的例子,这里的Student类和上文中的一样:

public class Demo1 {
    //私有方法
    private static void reflectPrivateMethod(){
        Class a;
        try {

            a = Class.forName("Student");

            //(私有方法名,私有方法的参数类型...)
            Method method = a.getDeclaredMethod("set", String.class, int.class);
            method.setAccessible(true);//因为私有...
            Student student = (Student) a.newInstance();

            method.invoke(student,"pppp",10);//调用私有方法 (对象,传参...)
            
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}

五,反射的优点与缺点

优点:

  1. 可以得到任意一个类的所有属性和方法,并且可以将其调用。
  2. 增加了程序的灵活性和扩展性,降低耦合性,提高自适应能力。
  3. 反射已经在很多框架中应用。

缺点:

  1. 效率很低,我们一般实例化一个对象只要调用一个方法,但是反射却调用不只一个方法,会占用更多的资源。
  2. 反射会导致维护的困难,反射代码比一般的代码更加复杂。

你可能感兴趣的:(java,servlet,开发语言)