本文是Java反射篇,学习于廖雪峰的Java教程

Java反射

1.Class类

  • 反射:通过Class实例获取相关类信息的方法称为反射。

  • JVM会在执行过程中动态加载类到内存,并为其创建一个Class类型的实例,并且该Class实例只能在JVM内部创建。

  • 如何获取一个Class实例

    • 通过一个类的静态变量class获取,如String,class
    • 通过实例变量调用getClass()方法。
    • 通过Class类的静态Class.forName()方法,例Class.forName(String.lang.String),其中参数中的类名要为完整类名。
  • Class实例的比较,可以用==比较,原因是Class实例在JVM中是唯一的。

  • 准确判断两个类型是否为同一类型可用==比较。

  • 数组例如String[ ]也可以创建Class实例,而且不同于String.class

  • 此外,JVM也为基本类型创建了Class实例,例如int.class

  • 可通过一个Class实例调用newInstance()方法创建一个对应类型的实例,但只能调用该类的无参数构造方法,例如:

Class cls = String.class;
String s = (String) cls.newInstance();
  • JVM的动态加载:JVM在执行Java程序的时候,并不会一次性加载所有class到内存,而是会优先把首先用到的class加载进内存,尚未需要的class并不会被加载。

2.Field实例

  • 获取Filed实例

    • Field getField(name)参数为字段名,获取public实例字段,包括父类。
    • Filed getDeclaredField(name)参数为字段名,只获取当前类的所有Field实例字段。
    • Field[] getFields()获取所有public实例字段,包括父类。
    • Field[] getDeclaredFields()只获取当前类的所有public实例字段。
  • Field实例包含的几个方法

    • getName()获取字段名称。
    • getType()获取字段类型。
    • getModifiers()获取字段修饰符,会返回一个int类型的数值,最后再通过静态Modifier.isPublic()等方法判断是否为public 等修饰符。
  • 获取字段的值可通过Field实例调用get(p)方法来获取字段的值,其中参数p为原类型实例。

  • setAccesible(true)方法可以设置某非public字段的值可访问。

  • set(Object,Objie)方法可用来设置字段的值,其中第一个参数为原类型实例,第二个参数为待修改的值。

  • 示例代码

import java.lang.reflect.Field;
public class Main {

    public static void main(String[] args) throws Exception {
        Person p = new Person("Xiao Ming");
        System.out.println(p.getName()); // "Xiao Ming"
        Class c = p.getClass();
        Field f = c.getDeclaredField("name");
        f.setAccessible(true);
        f.set(p, "Xiao Hong");
        System.out.println(p.getName()); // "Xiao Hong"
    }
}

class Person {
    private String name;

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

    public String getName() {
        return this.name;
    }
}

3.Method实例

  • 获取Method实例

    • Method getMethod(name,Class),第一个参数为原类型实例,第二个参数为方法名name的参数的数据类型所对应的Class实例,获取public实例方法(包括父类)。
    • Method getDeclaredMethod(name, Class...)只获取当前类的实例方法。
    • Method[] getMethod()获取所有public实例方法(包括父类)。
    • Method[] getDeclaredMethod()只获取当前类的所有实例方法。
  • Method实例包含的几个方法

    • getName()获取方法名字。
    • getReturnTyoe()获取方法的返回类型。
    • getParameterTypes()获取方法的参数类型,是一个Class数组。
    • getModifies()获取方法的修饰符。
    • invoke()方法相当于调用该实例方法,第一个参数为调用该方法的实例,并且参数要与实例方法参数一致。
  • setAccesible(true)可设置某非public方法可访问。

  • 通过反射调用方法时,仍然遵循多态原则。

4.Constructor实例

  • 获取Constructor实例
    • Constructor getConstructor()获取当前类的某个public构造方法。
    • Constructor getDeclaredConstructor()获取当前类的某个构造方法。
    • Constructor[] getConstructor()获取当前类的所有public构造方法。
    • Constructor[] getConstructor()获取当前类的所有public构造方法。
  • Constructo实例可以调用拥有多种参数的构造方法。
  • 设置setAccessible(true)来访问非public构造方法。
  • 代码示例
import java.lang.reflect.Constructor;
public class Main {
    public static void main(String[] args) throws Exception {
        // 获取构造方法Integer(int):
        Constructor cons1 = Integer.class.getConstructor(int.class);
        // 调用构造方法:
        Integer n1 = (Integer) cons1.newInstance(123);
        System.out.println(n1);

        // 获取构造方法Integer(String)
        Constructor cons2 = Integer.class.getConstructor(String.class);
        Integer n2 = (Integer) cons2.newInstance("456");
        System.out.println(n2);
    }
}

5.反射与继承关系

  • getSuperClass()方法可以获取子类的父类。
  • getInterfaces()方法可以获取子类实现的接口类,注意这个方法的返回类型是Class[]数组,也只能获取当前类的接口,不包括父类。
  • isAssignableForm()方法可以判断两个Class实例向上转型是否成功。