Skip to content

JAVA的反射机制

1、什么是JAVA的反射机制

Java 反射是 Java 被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运 行时透过 Reflection APIs 取得任何一个已知名称的 class 的内部信息,包括其

modifiers(诸如 public, static 等)、superclass(例如 Object)、实现之 interfaces(例如 Cloneable),也包括 fields 和 methods 的所有信息,并可于运行 时改变 fields 内容或唤起 methods。

Java 反射机制容许程序在运行时加载、探知、使用编译期间完全未知的 classes。

换言之,Java 可以加载一个运行时才得知名称的 class,获得其完整结构。

2、JDK 中提供的 Reflection API

Java 反射相关的 API 在包 java.lang.reflect

API描述
Member 接口该接口可以获取有关类成员(域或者方法)后者构造函数的信息。
AccessibleObject 类该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控 制检查的能力。
Array 类该类提供动态地生成和访问 JAVA 数组的方法。
Constructor 类提供一个类的构造函数的信息以及访问类的构造函数的接口。
Field 类提供一个类的域的信息以及访问类的域的接口。
Method 类提供一个类的方法的信息以及访问类的方法的接口。
Modifier类提供了 static 方法和常量,对类和成员访问修饰符进行解码。
Proxy 类提供动态地生成代理类和类实例的静态方法。

3、JAVA 反射机制提供了什么功能

Java 反射机制提供如下功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判段任意一个类所具有的成员变量和方法
  • 在运行时调用任一个对象的方法
  • 在运行时创建新类对象
  • 在使用 Java 的反射功能时,基本首先都要获取类的 Class 对象,再通过 Class 对象获取其他的对象。

1、获取类的 Class 对象

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。获取类的 Class 对象有多种方式:

1、调用 getClass

java
Boolean var1 = true;
Class<?> classType2 = var1.getClass();
System.out.println(classType2);
// 输出:class java.lang.Boolean

2、运用 .class

java
Class<?> classType4 = Boolean.class;
System.out.println(classType4);
// 输出:class java.lang.Boolean

3、运用 static method Class.forName()

java
Class<?> classType5 = Class.forName("java.lang.Boolean");
System.out.println(classType5);
// 输出:class java.lang.Boolean

4、运用primitive wrapper classes classes语法

java
Class<?> classType3 = Boolean.TYPE;
System.out.println(classType3);
// 输出:boolean
// 这里返回的是 原生类型,和 Boolean.class 返回的不同

2、获取类的 Fields

可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。

JAVA 的 Class<T>类提供了几个方法获取类的属性。

方法描述
public Field getField(String name)返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段
public Field[] getFields()返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段
public Field getDeclaredField(String name)返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段
public Field[] getDeclared Fields()返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段
java
public class Person {

    private String name;
    public int age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", 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 Person(String name, int age) {

        this.name = name;
        this.age = age;
    }

    private Person(String name) {
        this.name = name;
    }

    public Person() {
        System.out.println("Person()");
    }

    public void show(){
        System.out.println("你好,我是一个人");
    }

    private String showNation(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }
}
java
Class<?> clazz = Person.class;

//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for(Field f : fields){
  System.out.println(f);
}

//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
  System.out.println(f);
}

可见 getFields 和 getDeclaredFields 区别:

  • getFields 返回的是申明为 public 的属性,包括父类中定义,
  • getDeclaredFields 返回的是指定类定义的所有定义的属性,不包括父类的。

3、获取类的 Method

通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法

方法描述
public Method getMethod(String name,Class<?>... parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公 共成员方法
public Method[] getMethods()返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表 示的类或接口(包括那些由该类或接口声明的以及从超 类和超接口继承的那些的类或接口)的公共 member 方法
public Method getDeclared Method(String name,Class<?> ... parameterTypes)返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指 定已声明方法
public Method[] getDeclaredMethods()返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接 口声明的所有方法,包括公共、保护、默认(包)访问 和私有方法,但不包 括继承的方法
java
Class clazz = Person.class;

//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
  System.out.println(m);
}
System.out.println();
//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
  System.out.println(m);
}

4、获取类的 Constructor

通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例

方法描述
public Constructor<T> getConstructor(Class<?>... parameterTypes)返回一个Constructor对象,它反映此 Class 对象所表示的类的指定公共构造方法
public Constructor<?> [] getConstructors()返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class对象所表示的类的所有公共构造方法
public Constructor<?> getDeclaredConstruct or(Class<?>... parameterTypes)返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法
public Constructor<?>[] getDeclaredConstructors()返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声 明的所 有构造方法 。它们是公共 、保护 、默认( 包 )访问和私有构造方法
java
Class clazz = Person.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor c : constructors){
  System.out.println(c);
}

//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for(Constructor c : declaredConstructors){
  System.out.println(c);
}

5、新建类的实例

1、调用类的 Class 对象的 newInstance 方法,该方法会调用对象的默认

java
Class<Person> clazz = Person.class;
/*
        newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。

        要想此方法正常的创建运行时类的对象,要求:
        1.运行时类必须提供空参的构造器
        2.空参的构造器的访问权限得够。通常,设置为public。

        在javabean中要求提供一个public的空参构造器。原因:
        1.便于通过反射,创建运行时类的对象
        2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器
         */
Person obj = clazz.newInstance();
System.out.println(obj);

2、调用默认 Constructor 对象的 newInstance 方法

java
Class clazz = Person.class;
Constructor constructor = clazz.getConstructor();
Object instance = constructor.newInstance();

3、调用带参数 Constructor 对象的 newInstance 方法

java
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
Object newInstance = declaredConstructor.newInstance("12", 12);

6、调用类的函数

通过反射获取类 Method 对象,调用 Field 的 Invoke 方法调用函数。

java
//调用方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(p);

//通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
//调用私有的构造器
Constructor cons1 = clazz.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1 = (Person) cons1.newInstance("Jerry");
System.out.println(p1);

//调用私有的方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国")
System.out.println(nation);

7、设置/获取类的属性值

通过反射获取类的 Field 对象,调用 Field 方法设置或获取值

java
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();

//获取指定的属性:要求运行时类中属性声明为public
//通常不采用此方法
Field id = clazz.getField("id");