我们知道在运行时通过反射可以准确获取到注解信息,其实以上类(Class,Method,Field,Constructor等)都直接或间接实现了AnnotatedElement接口,并实现了它定义的方法,AnnotatedElement接口的作用主要用于表示正在JVM中运行的程序中已使用注解的元素,通过该接口提供的方法可以获取到注解信息。
java.lang.Class 类在Java反射中,最重要的是Class这个类了。Class本身也是一个类。当程序想要使用某个类时,如果此类还未被加载到内存中,首先会将类的class文件字节码加载到内存中,并将这些静态数据转换为方法区的运行时数据结构,然后生成一个Class类型的对象(Class对象只能由系统创建),一个类只有一个Class对象,这个对象包含了类的结构信息。我们可以通过这个对象看到类的结构。每个类的实例都会记得自己是由哪个Class实例所生成的。
通过Class对象可以知道某个类的属性,方法,构造器,注解,以及实现了哪些接口等信息。注意,只有class,interface,enum,annotation,primitive type,void,[] 等才有Class对象。
package com.nobody; import java.lang.annotation.ElementType; import java.util.Map; public class TestClass { public static void main(String[] args) { // 类 Class<MyClass> myClassClass = MyClass.class; // 接口 Class<Map> mapClass = Map.class; // 枚举 Class<ElementType> elementTypeClass = ElementType.class; // 注解 Class<Override> overrideClass = Override.class; // 原生类型 Class<Integer> integerClass = Integer.class; // 空类型 Class<Void> voidClass = void.class; // 一维数组 Class<String[]> aClass = String[].class; // 二维数组 Class<String[][]> aClass1 = String[][].class; // Class类也有Class对象 Class<Class> classClass = Class.class; System.out.println(myClassClass); System.out.println(mapClass); System.out.println(elementTypeClass); System.out.println(overrideClass); System.out.println(integerClass); System.out.println(voidClass); System.out.println(aClass); System.out.println(aClass1); System.out.println(classClass); } } // 输出结果 class com.nobody.MyClass interface java.util.Map class java.lang.annotation.ElementType interface java.lang.Override class java.lang.Integer void class [Ljava.lang.String; class [[Ljava.lang.String; class java.lang.Class获取Class对象的方法
如果知道具体的类,可通过类的class属性获取,这种方法最安全可靠并且性能最高。Class clz = User.class;
通过类的实例的getClass()方法获取。Class clz = user.getClass();
如果知道一个类的全限定类名,并且在类路径下,可通过Class.forName()方法获取,但是可能会抛出ClassNotFoundException。Class clz = Class.forName("com.nobody.User");
内置的基本数据类型可以直接通过类名.Type获取。Class<Integer> clz = Integer.TYPE;
通过类加载器ClassLoader获取
Class类的常用方法
public static Class<?> forName(String className):创建一个指定全限定类名的Class对象
public T newInstance():调用Class对象所代表的类的无参构造方法,创建一个实例
public String getName():返回Class对象所代表的类的全限定名称。
public String getSimpleName():返回Class对象所代表的类的简单名称。
public native Class<? super T> getSuperclass():返回Class对象所代表的类的父类的Class对象,这是一个本地方法
public Class<?>[] getInterfaces():返回Class对象的接口
public Field[] getFields():返回Class对象所代表的实体的public属性Field对象数组
public Field[] getDeclaredFields():返回Class对象所代表的实体的所有属性Field对象数组
public Field getDeclaredField(String name):获取指定属性名的Field对象
public Method[] getDeclaredMethods():返回Class对象所代表的实体的所有Method对象数组
public Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回指定名称和参数类型的Method对象
myClassClass.getDeclaredConstructors();:返回所有Constructor对象的数组
public ClassLoader getClassLoader():返回当前类的类加载器
在反射中经常会使用到Method的invoke方法,即public Object invoke(Object obj, Object... args),我们简单说明下:
第一个Object对应原方法的返回值,若原方法没有返回值,则返回null。
第二个Object对象对应调用方法的实例,若原方法为静态方法,则参数obj可为null。
第二个Object对应若原方法形参列表,若参数为空,则参数args为null。
若原方法声明为private修饰,则调用invoke方法前,需要显示调用方法对象的method.setAccessible(true)方法,才可访问private方法。
反射操作泛型