JAVA的反射机制

Posted 我永远信仰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA的反射机制相关的知识,希望对你有一定的参考价值。

JAVA的反射机制

反射是框架设计的灵魂。

1、反射机制

反射是一种功能强大且复杂的机制,射机制可以用来:

  • 在运行中分析类的能力
  • 在运行中查看对象
    • 在运行状态中,对于任意一个类,都能够查看这个类的所有属性和方法
    • 在运行状态中,对于任意一个对象,都能够调用他的任意一个方法和属性
  • 实现通用的数组操作代码,
  • 利用Method对象。

反射的应用场景

1、Spring 实例化对象:当程序启动时,Spring 会读取配置文件applicationContext.xml并解析出里面所有的标签实例化到IOC容器中。
2、反射 + 工厂模式:通过反射消除工厂中的多个分支,如果需要生产新的类,无需关注工厂类,工厂类可以应对各种新增的类,反射可以使得程序更加健壮。
3、JDBC连接数据库:使用JDBC连接数据库时,指定连接数据库的驱动类时用到反射加载驱动类

2、Class类

1.在程序运行期间,java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。

2.这个信息跟踪着每个对象所属的类。

3.可以通过专门的Java类来访问这些信息,就是Class类。

3、如何获得Class类型的实例?

假设有一个学生类

public class Student {
    private String name;
    private int age;
    private List<String> hobby;

    public Student() {
    }

    public Student(String name, int age, List<String> hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    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 List<String> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\\'' +
                ", age=" + age +
                ", hobby=" + hobby +
                '}';
    }
}

三种方法获取学生类的Class对象:

1.所有类都继承Object类,可以调用Object类中的getClass()方法会返回一个Class类型的实例。

​ 最常用的Class方法是getName,这个方法将会返回类的名字。

Student student = new Student();//这里产生了两个对象,一个是Student,一个是Class
Class<? extends Student> stuClass = student.getClass();//获取Class对象
System.out.println(stuClass.getName());//输出 reflect.Student。类的全限定名=包名+类名,reflect是包名

2.任何数据类型都有一个静态的class属性,比如int.class (小写)

Class studentClass2 = Student.class;
System.out.println(studentClass2.getName());//输出 reflect.Student

3.还可以调用Class类的静态方法forName()来获取类名对应的Class对象。(常用)

  • 需要传的参数是类的全限定名,否则会出现异常。
  • 需要放在try/catch块中
  • 只有在className是类名或者接口时才能够执行,否则,会抛出一个checked exception(已检测异常)
try {
    String className="reflect.Student";
    Class studentClass3 = Class.forName(className);
    System.out.println(studentClass3.getName());//输出 reflect.Student
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

在运行期间,一个类,只有一个Class对象产生。

可以用==运算符实现两个类对象比较的操作。

System.out.println(studentClass == studentClass2);//true
System.out.println(studentClass2 == studentClass3);//true

4、构造类的实例化对象

可以通过反射来构造一个类的实例。

有两种方法

1、Class对象调用newInstance()方法。

结合forName使用

String className = "reflect.Student";
Class<?> aClass = Class.forName(className);
Student student = (Student) aClass.newInstance();
student.setAge(1);
System.out.println(student.getAge());//输出1

这里没有new关键字,但是也能实例化一个Student。

注意:

newInstance方法调用默认的构造器(无参)来初始化新创建的对象,如果这个类没有默认的构造器(声明了有参的构造器且没有显式声明无参),则会抛出一个异常。

如果需要以这种方式向希望按照名称创建的类的构造器提供参数,则使用下面这种方法。

2、Constructor 构造器调用newInstance()方法

通过显式构造方法构造实例,需要提前从Class中调用getConstructor()方法获取对应的构造器,通过构造器去实例化对象。

List<String> list = new ArrayList<>();
list.add("篮球");		//Student的第三个参数
String className = "reflect.Student";
Class<?> aClass = Class.forName(className);
//通过getConstructor()获取对应的参数的构造器
Constructor<?> constructor = aClass.getConstructor(String.class, int.class, List.class);
constructor.setAccessible(true);
//使用该构造器去实例化对象。
Student  student = (Student) constructor.newInstance("赵东来", 18, list);
System.out.println(student);

/*输出:
Student{name='赵东来', age=18, hobby=[篮球]}
*/

5、获取类的所有信息

在这里插入图片描述

1、获取类中的Field(变量)

  • getField(String name)

    返回一个由 name 指定的该类的 Field 公共成员对象 。

  • getDeclaredField(String name)

    返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称。

  • getDeclaredFields()

返回 Field 对象的一个数组。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段

2、获取类中的Constructor(构造器)

  • getConstructor(Class<?>... parameterTypes)

    返回与指定的 parameterTypes 相匹配的公共构造方法的 Constructor 对象

  • getConstructors()

    返回表示此类公共构造方法的 Constructor 对象数组

  • getDeclaredConstructor(Class<?>... parameterTypes)

    带有指定参数列表的构造方法的 Constructor 对象

  • getDeclaredConstructors()

    表示此类所有已声明的构造方法的 Constructor 对象的数组

3、获取类中的Method(普通方法)

  • getMethod(String name, Class<?>... parameterTypes)

    • 与指定的 name 和 parameterTypes 匹配的 公共成员Method 对象

    • name 参数是一个 String,用于指定所需方法的简称。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes 为 null,则按空数组处理

  • getMethods()

    返回一个包含某些 Method 对象的数组,包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口的公共 member 方法。

  • getDeclaredMethod(String name, Class<?>... parameterTypes)

    返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

  • getDeclaredMethods()
    返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

以上是关于JAVA的反射机制的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

java 反射代码片段

深入理解java的反射机制

Java反射机制

Java核心技术梳理-类加载机制与反射