小白都能学会的Java注解与反射机制 (3)

我们知道在运行时通过反射可以准确获取到注解信息,其实以上类(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方法。

反射操作泛型

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzgwy.html