时不时回顾一下基础知识,也算是温故而知新,每次都记笔记,想想还是发出来记录一下,写错的地方求大神们指正。
动态语言,所谓动态是指在运行时允许程序修改自身结构或者变量类型。
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<java.lang.String> 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()); } }