时不时回顾一下基础知识,也算是温故而知新,每次都记笔记,想想还是发出来记录一下,写错的地方求大神们指正。


动态语言,所谓动态是指在运行时允许程序修改自身结构或者变量类型。

Java不是动态语言,但是提供了强大的反射机制,可以一定程度上达到动态语言的效果。

Java反射机制的目的有两点:

运行状态下获取任意一个类的所有属性与方法(动态获取信息)

能够调用任意一个对象的方法和属性(动态调用对象方法) 


反射机制提供了运行时的灵活性,只要知道某个类,就可以反射创建新的对象和调用对象的方法等,但提升灵活性的同时,反射的效率相比于直接在代码中生成对象或调用方法要差一些,使用时应该权衡效率与灵活性。


Java Reflection API基本功能

获取类的内部结构,包括构造方法、声明的属性、定义的方法、注解等,主要通过java.lang.Class类的对象来完成。已下面这个MyClass类为例。

public class MyClass {

    private String className;

    public MyClass(String className) {
        this.className = className;
    }

    public MyClass() {

    }

    public String append(String number) {
        return className + number;
    }
}

一般生成对象以及调用方法:

MyClass myClass = new MyClass("Class A");  //创建对象
System.out.println(myClass.append("100")); //结果:Class A100

通过反射生成对象以及调用方法:

只要获得java.lang.Class类的对象,比如MyClass.class,就可以通过反射获得该类中构造方法、属性和方法,分别有三类方法:

getConstructors()/getConstructor()  

getFields()/getField()

getMethods()/getMethod()

这三类方法对应的还有getDeclared***()方法,区别在于后者只会获取当前类自己声明的构造方法、属性和方法,而前者则会获取通过继承得到的元素。 

//获取指定参数类型的构造函数, 比如MyClass类有一个带String参数的构造函数
Constructor constructor = MyClass.class.getDeclaredConstructor(String.class);
MyClass myClass = (MyClass)constructor.newInstance("Class B");   //生成对象
//获取类的所有构造函数
//只会获取明确声明的构造函数,比如无参的构造函数,如果不声明,则不会被获取到
Constructor[] constructors = MyClass.class.getDeclaredConstructors();

//获取类中声明的方法
Method[] methods = MyClass.class.getDeclaredMethods();
Method method = MyClass.class.getDeclaredMethod("append", String.class);
System.out.println(method.invoke(myClass, "100")); //调用方法

//获取类中声明的属性字段
Field[] fields = MyClass.class.getDeclaredFields();
Field field = MyClass.class.getDeclaredField("className");

//Array提供了数组类型的反射
Object array = Array.newInstance(String.class, 5);
Array.set(array, 0, "A");
Array.set(array, 1, "B");
System.out.println(Array.get(array, 1));


带泛型的反射

Java5开始引入了泛型,因此Java反射机制也进行了一定的调整来适应泛型。

在Constructor和Field类中都有一个signature字段,通过这个字段可以在运行时获取到泛型参数类型。 

//获取带泛型的属性字段
Field field = MyClass.class.getDeclaredField("students");
//获得类型,如果有泛型则返回带泛型的类型,否则返回类型
//通过Field类的signature字段来判断是否带泛型
//返回 java.util.List
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
    System.out.println(type);
    ParameterizedType parameterizedType =(ParameterizedType) type;
    //获取参数类型
    Type[] types = parameterizedType.getActualTypeArguments();
    for (Type t : types) {
        System.out.println(t.getTypeName());
    }
}