Java反射机制构件详解

Type系列

reflect包内存在一系列用于表示类型的接口,它们都继承自Type。每个接口的含义如下:

  • Type:广义的“类型”。它是所有类型的共同超接口,包括原始类型、参数化类型、数组类型、类型变量等。
  • ParameterizedType:“参数化类型”。举例:Collection<String>。
  • TypeVariable:“类型变量”。举例:Collection<T>。
  • WildcardType:“通配符”。举例:Collection<? extends Number>。
  • GenericArrayType:“泛型数组类型”。它包含的元素可以是参数化类型或者类型变量。

AnnotatedElement

public interface AnnotatedElement

AnnotatedElement接口的含义是“可被注解的”,这个接口使得利用反射机制读取注解成为可能。在java.lang.reflect包中,所有支持注解的元素都实现了AnnotatedElement接口,比如Constructor、Method、Parameter以及不在reflect包内的Class。
AnnotatedElement接口中定义了如下方法:

boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

<T extends Annotation> T getAnnotation(Class<T> annotationClass)

Annotation[] getAnnotations()

<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)

<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)

Annotation[] getDeclaredAnnotations()

<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)

isAnnotationPresent(Class <? extends Annotation> annotationClass)方法判断参数annotationClass指向的注解类型是否存在于AnnotatedElement对象上,若存在则返回true,不存在则返回false。
剩下的六个get方法名字非常相似。为便于理解,可以按照以下几种方法将它们分组:
(1)有无Declared:

  • 有Declared的get方法只会获取到直接加在这个类上的注解,不会获取到从超类继承来的注解。
  • 没有Declared的get方法除了能获取到直接加在这个类上的注解,还能获得从超类继承来的注解(当然注解本身必须是有@Inherited注解的,即可继承的)。

(2)是否需要传入Class对象:

  • 需要传入Class对象的get方法只能获取到对应类型的注解。
  • 不需要传入Class对象的get方法能获取到所有类型的注解。

(3)getAnnotation/getAnnotations:

  • getAnnotation返回的是单个Annotation对象。
  • getAnnotations返回的是Annotation数组。

(4)结尾有无ByType:

  • 有ByType的get方法会考虑重复注解(Java 8),能够返回所有该类型的注解。
  • 没有ByType的get方法不考虑重复注解。

Member

public interface Member 

Member接口的含义是“成员”,能够作为某个类的成员的元素都实现了该接口,如Constructor、Method、Field。
Member接口中定义了以下方法:

//获得声明该成员的类或接口的Class对象
public Class<?> getDeclaringClass()

//获得该成员的修饰符
//可用reflect包中的Modifier提供的方法解析
public int getModifiers()

//获得该成员的名称
public String getName()

//该成员是否是编译器引入的
public boolean isSynthetic()

GenericDeclaration

public interface GenericDeclaration
implements AnnotatedElement 

GenericDeclaration接口的含义是“支持泛型声明的”,即在声明时可以使用泛型的元素,比如Class、Constructor、Method。
GenericDeclaration接口中只声明了一个方法:

//返回一个TypeVariable数组,包含声明的所有泛型元素对应的TypeVariable对象
TypeVariable[]<?> getTypeParameters ()

示例:

class A<T,U>{
    private T t;
    private U u;
    public A(T t, U u){
        this.t = t;
        this.u = u;
    }
}

public static void main(String[] args){
    Class<?> clazzA = A.class;
    System.out.println(Arrays.toString(
            clazzA.getTypeParameters()));
}

输出结果:
[T, U]

AccessibleObject

public class AccessibleObject
extends Object implements AnnotatedElement 

AccessibleObject类的含义是“可被访问的”,它提供了突破Java语言的访问权限检查的能力。AccessibleObject实现了 AnnotatedElement接口。
AccessibleObject类提供了以下方法(这里以及后文都不会重复出现继承或实现接口得到的方法)

//是否能够访问到
public boolean isAccessible()

//设置访问权限,若设置失败则抛出SecurityException异常
public void setAccessible(boolean flag) throws SecurityException

//设置一组对象的访问权限,若设置失败则抛出SecurityException异常
public static void setAccessible(AccessibleObject[] array, boolean flag) throws SecurityException

Field

public final class Field
extends AccessibleObject implements Member 

Field类的含义是“域”,包含类域(static的)与实例域(非static的)。
Field类提供了相当多的方法,下面分类说明:
(1)从对象中获取该域对应的对象或值:

//省略throws IllegalArgumentException, IllegalAccessException
public Object get(Object obj)
public boolean getBoolean(Object obj)
public byte getByte(Object obj)
public char getChar(Object obj)
public double getDouble(Object obj)
public float getFloat(Object obj)
public int getInt(Object obj)
public long getLong(Object obj)
public short getShort(Object obj)

注意点:

  • IllegalArgumentException:obj对象不是声明该域的类或接口的实例,(仅适用于原始类型)或者无法通过宽化(如short→int)获得正确类型的返回值时抛出。
  • IllegalAccessException:访问权限不足时抛出。
  • 如果该域是静态域,那么可以传入null。如果声明该域的类尚未初始化,那么会先初始化该类。
  • 如果该域不是静态域,如果传入的是null会抛出 NullPointerException。
  • 即便该域在子类中被隐藏了,返回的还是父类中的域对应的对象或值。

示例:

class A{
    public int x;
    public int y;

    A(int x,int y){
        this.x = x;
        this.y = y;
    }
}

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException{
    A a = new A(2, 3);

    Class<?> clazzA = A.class;
    for(Field field : clazzA.getFields()){
        System.out.println(field.getName() + " = " + field.get(a));
    }

}

输出:
x = 2
y = 3

(2)设置对象中该域对应的对象或值:

//省略throws IllegalArgumentException, IllegalAccessException
public Object set(Object obj, Object value)
public boolean setBoolean(Object obj, boolean value)
public byte setByte(Object obj, byte value)
public char setChar(Object obj, char value)
public double setDouble(Object obj, double value)
public float setFloat(Object obj, float value)
public int setInt(Object obj, int value)
public long setLong(Object obj, long value)
public short setShort(Object obj, short value)

关于异常抛出以及静态域的处理规则和get相同。
(3)其他

//返回该域对应的Class对象
public Class<?> getType()

//返回表示该域类型的Type对象
//可能包含泛型
public Type getGenericType() 

//返回该域的名称
public String getName()

//判断该域是否为枚举常量
public boolean isEnumConstant()

Executable

public abstract class Executable
extends AccessibleObject implements Member, GenericDeclaration 

Executable类的含义是“可执行的”,它是Method与Constructor的超类。
Executable类提供了以下方法:
(1)获取Executable自身相关信息:

//返回该Executable的名称
public abstract String getName()

(2)获取参数列表相关信息:

//返回一个Type数组,表示该Executable的参数类型
//参数类型可能包含泛型
public Type[] getGenericParameterTypes()

//返回参数个数
public int getParameterCount()


//返回一个Parameter数组,表示该Executable的参数列表
public Parameter[] getParameters()

//返回一个Class数组,表示该Executable的参数列表
public abstract Class<?>[] getParameterTypes()

//返回一个TypeVariable数组,表示该Executable的类型变量列表
//例:public <T,U> void some() 中的<T,U>
public abstract TypeVariable<?>[] getTypeParameters()

(3)异常相关:

//返回一个Class数组,表示该Executable抛出的异常类型
public abstract Class<?>[] getExceptionTypes();

//返回一个Type数组,表示该Executable抛出的异常类型
//异常类型可能包含泛型
public Type[] getGenericExceptionTypes()

Parameter

public final class Parameter
extends Object implements AnnotatedElement 

Parameter类的含义是“参数”。类中提供了访问该参数的名称、修饰符以及其他属性的方法。

//返回声明该参数的Executable
Executable getDeclaringExecutable ()

//返回该参数的修饰符
//需要用Modifier类解析
int getModifiers ()

//返回该参数名称
String getName ()

//返回该参数类型
Class<?> getType ()
Type getParameterizedType ()

//该参数是否代表一个变长参数列表
boolean isVarArgs ()

Method

public final class Method
extends Executable 

Method类的含义是“方法”。在Executable类的基础之上,它还提供了以下方法:
(1)获取方法的更多信息:

//获取该方法的注解成员的默认值
public Object getDefaultValue()

//获取该方法返回值对应的Class对象
public Class<?> getReturnType()

(2)invoke方法:

Object invoke (Object obj, 
                Object... args)

通过指定的对象和参数列表调用该Method对象对应的方法。
每个单独的参数都会被自动解包来与原始类型匹配。
在必要的情况下,原始类型和引用类型都会被转换成方法要求的类型。
如果该方法是一个静态方法,那么指定的对象obj会被忽略,也可以传入null。
如果该方法不需要参数,那么参数列表args长度可以是0,也可以传入null。
支持自动宽化(short→int),不支持自动窄化(long→int)
如果该方法是一个静态方法,并且该方法所属的类还未被加载,那么会自动加载该类。
如果该方法调用成功,那么会返回相应的返回值。如果返回值是原始类型则会被自动包装,但如果返回值是原始类型数组则不会自动包装数组元素。
void方法会返回null。
可能抛出的异常:

  • IllegalAccessException:访问权限不足;
  • IllegalArgumentException:方法是实例方法,而传入的obj不是声明该方法的类或接口(包括子类);参数列表不匹配;
  • InvocationTargetException:方法调用过程中抛出了异常;
  • NullPointerException:方法是实例方法,而传入的obj为null;
  • ExceptionInInitializerError:初始化失败。

Constructor

public final class Constructor
extends Executable 

Constructor类的含义是“构造器”。它提供的方法和Method类基本相同,最主要的区别在于多了newInstance方法(替换了invoke)。

T newInstance (Object... initargs)

这个方法能够通过指定的参数列表调用该Constructor指向的构造器,并返回该构造器所属的类的一个实例。
每个单独的参数都会被自动解包来与原始类型匹配。
在必要的情况下,原始类型和引用类型都会被转换成要求的类型。
如果构造器需要的参数个数为0,那么initargs的长度可以为0,也可以是null。
如果该构造器所属的类是一个非静态内部类,那么参数列表的第一个需要传入外部类的一个实例。
如果该构造器所属的类尚未初始化,那么会自动初始化该类。
如果构造器正常结束,那么会返回一个新对象。
可能抛出的异常:

  • IllegalAccessException:访问权限不足;
  • IllegalArgumentException:参数列表不匹配;构造器属于一个枚举类;
  • InstantiationException:该构造器所属的类是抽象类;
  • InvocationTargetException:构造器抛出了异常;
  • ExceptionInInitializerError:初始化失败。

Array

public final class Array

Array类的含义是“数组”。类中包含了一系列设置与获取某个位置的值以及创建新数组的方法。
(1)获取数组某个位置处的值或对象

//省略throws IllegalArgumentException, ArrayIndexOutOfBoundsException
public static Object get(Object array, int index)
public static boolean getBoolean(Object array, int index)
public static byte getByte(Object array, int index)
public static char getChar(Object array, int index)
public static double getDouble(Object array, int index)
public static float getFloat(Object array, int index)
public static int getInt(Object array, int index)
public static long getLong(Object array, int index)
public static short getShort(Object array, int index)

可能抛出的异常:

  • NullPointerException:array为null;
  • IllegalArgumentException:array不为数组类型,数组元素与返回值类型不匹配;
  • ArrayIndexOutOfBoundsException:index是负数;index大于等于数组长度。

(2)设置数组某个位置处的值或对象

//省略throws IllegalArgumentException, ArrayIndexOutOfBoundsException
public static Object set(Object array, int index, Object value)
public static boolean setBoolean(Object array, int index, boolean z)
public static byte setByte(Object array, int index, byte b)
public static char setChar(Object array, int index, char c)
public static double setDouble(Object array, int index, double d)
public static float setFloat(Object array, int index, float f)
public static int setInt(Object array, int index, int i)
public static long setLong(Object array, int index, long l)
public static short setShort(Object array, int index, short s)

可能抛出的异常:

  • NullPointerException:array为null;
  • IllegalArgumentException:array不为数组类型,数组元素与参数类型不匹配;
  • ArrayIndexOutOfBoundsException:index是负数;index大于等于数组长度。

(3)获取数组长度:

public static int getLength(Object array)

(4)创建新数组:

//根据数组元素类型和数组长度创建新数组
public static Object newInstance (Class<?> componentType, 
                int length)
                throws IllegalArgumentException, NegativeArraySizeException

//根据数组元素类型与数组维数创建新数组
public static Object newInstance (Class<?> componentType, 
                int... dimensions)
                throws IllegalArgumentException, NegativeArraySizeException

可能抛出的异常:

  • NullPointerException: componentType参数为null;
  • IllegalArgumentException:数组维数超过255;
  • NegativeArraySizeException:维数或长度是负数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值