java.lang.reflect包简析

    java.lang.reflect是“反射”包,其中定义了各个元数据的类。其继承关系如下图所示:

一、最底层的接口

    几个蓝色色框中,定义了最底层的几个接口:

    AnnotatedElement接口,这个接口中的方法,用来获取元素上的注解(如果是在框架中,通常是被定义为“运行时可见”的注解)。可以被注解的元素均继承了这个接口,如Method、Field、Class等。

    此类型可以用来:获得一个元素的所有注解、特定类型的注解,查看元素上是否存在这种注解。

 

    Type接口,代表一个类型。类型并非只有Class类,下面会讲到,还有别的类型(主要是和泛型的类型参数相关,类型参数的“擦除”并不是了无痕迹,在某些特定的情况下,仍然可以获取到泛型的类型参数信息)。

    此接口只有一个getTypeName方法,用来获取类型的名字。其他的功能都定义在子类中。

 

    Member接口,代表一个“成员”,从上面的图中可见,方法、构造器、字段三种元素继承了这一个接口。其中定义了两个常量:

  • PUBLIC,表示一个类型所有的“公有”成员,而不论这个成员是在这个类、还是这个类的基类中定义的。

  • DECLARED,表示这个类型中定义的成员,而不是从别的地方“继承”过来的,不论是public、protected或者private都行。

    这个接口中定义了一些方法,例如:获取成员的名字,获取成员的限定符(public、statis、final这一类,但是是一个int值。需要自己按位解析),是哪个类中直接定义的,是否是编译器产生的(一些方法可能是编译器自动产生的,而不是在代码中定义的,例如内部类相关的一些方法)

 

二、Type接口衍生的类型

    泛型有“擦除”的机制,这是很多人都知道的。但是,作为“局部变量”和“字段”的泛型实例对象,仍然有所不同,字段保留了更多的泛型信息。因此,下面的代码示例,都使用了类字段,而非局部变量。

1、ParameterizedType

    ParameterizedType接口,表示一个被参数化的类型。几个重要的方法有:

  • getRawType,得到参数化类型的原始类型,例如下面程序运行的结果,返回了Map.class
  • getActualTypeArguments,得到类型参数的列表

    示例代码如下:

public class Parameterized {
    public static void main(String[] argv) throws Exception {
        Class<MySelf> cls = MySelf.class;
        Field field = cls.getField("strs");
        ParameterizedType type = (ParameterizedType)field.getGenericType();

        System.out.println("getRawType:" + type.getRawType().getTypeName());
        Type[] types = type.getActualTypeArguments();

        for (Type t : types) {
            System.out.println("getActualTypeArguments:" + t.getTypeName());
        }

    }
}

class MySelf {
    public Map<String, Integer> strs;
}

运行结果如下:

getRawType:java.util.Map
getActualTypeArguments:java.lang.String
getActualTypeArguments:java.lang.Integer

2、WildcardType

    WildcardType表示一个类型通配符,例如?, ? extends Number, ? super XXX这样的类型参数。

    有两个重要方法:

  • getUpperBounds,返回? extends xxx中的类型
  • getLowerBounds,返回? super xxx中的类型

    示例代码如下:

public class Wildcard {
    public static void main(String[] argv) throws Exception {
        Class<WildcardInner> cls = WildcardInner.class;
        Field fa = cls.getField("a");
        Field fb = cls.getField("c");

        WildcardType wta = (WildcardType)((ParameterizedType)fa.getGenericType()).getActualTypeArguments()[0];
        System.out.println("wta:" + wta.getTypeName());
        System.out.println("upper:" + wta.getUpperBounds()[0]);

        WildcardType wtb = (WildcardType)((ParameterizedType)fb.getGenericType()).getActualTypeArguments()[0];
        System.out.println("wtb:" + wtb.getTypeName());
        System.out.println("lower:" + wtb.getLowerBounds()[0]);

    }
}

class WildcardInner {
    public List<? extends A> a;
    public Set<? super C> c;
}

class A {}

interface B {}

class C extends A implements B {}

    运行结果如下:

wta:? extends A
upper:class .A
wtb:? super C
lower:class C

3、GenericArrayType

    GenericArrayType表示一个数组类型,其组成元素是ParameterizedType,或者是TypeVariable。

    其只有一个方法:getGenericComponentType,得到元素的参数类型。

    示例代码如下:

public class GenericArray {

    public static void main(String[] argv) throws Exception {
        Class<GenericArrayInner> cls = GenericArrayInner.class;
        Field f = cls.getField("lists");
        GenericArrayType type = (GenericArrayType)f.getGenericType();
        ParameterizedType pType =  (ParameterizedType) type.getGenericComponentType();
        System.out.println(pType.getTypeName());
    }
}

class GenericArrayInner {
    public List<Integer>[] lists;
}

    运行结果:

java.util.List<java.lang.Integer>

三、Parameter

    Parameter代表方法、构造器的参数。

    需要在编译的时候,加上-parameters参数,才能通过getName方法,拿到参数的名称。

    Parameter类上,有用的方法有:

  • getName,得到参数的名称。但是注意要在编译的时候,加上-parameters参数。如果不加,得到的就是arg0,arg1这样的
  • getDeclaringExecutable,得到参数属于的方法或构造器
  • getType,得到参数的类型
  • getParameterizedType,得到参数化的类型
  • isVarArgs,是否是参数列表(String ... strs这样的参数,调用的时候参数数量不定,但是只能放在最后)
  • getModifier,得到修饰符int值(但是参数的修饰符,也只想到一个final,除此以外不知道能有什么了)

    示例代码如下:

public class ParameterTest {
    public static void main(String[] argv) throws Exception {
        Class<ParameterInner> cls = ParameterInner.class;
        Method method = cls.getDeclaredMethod("fun", int.class, List.class, String[].class);
        Parameter[] parameters = method.getParameters();
        for (Parameter p : parameters) {
            System.out.println("getName: " + p.getName());
            System.out.println("getDeclaringExecutable: " + p.getDeclaringExecutable());
            System.out.println("getParameterizedType: " + p.getParameterizedType());
            System.out.println("isVarArgs: " + p.isVarArgs());
            System.out.println("getModifiers: " + p.getModifiers());
            System.out.println("----");
        }
    }
}

class ParameterInner {
    private void fun(final int number, List<Double> detail, String ... strs) {
        //do nothing
    }
}

    运行结果:

getName: number
getDeclaringExecutable: private void my.reflect.ParameterInner.fun(int,java.util.List,java.lang.String[])
getParameterizedType: int
isVarArgs: false
getModifiers: 16
----
getName: detail
getDeclaringExecutable: private void my.reflect.ParameterInner.fun(int,java.util.List,java.lang.String[])
getParameterizedType: java.util.List<java.lang.Double>
isVarArgs: false
getModifiers: 0
----
getName: strs
getDeclaringExecutable: private void my.reflect.ParameterInner.fun(int,java.util.List,java.lang.String[])
getParameterizedType: class [Ljava.lang.String;
isVarArgs: true
getModifiers: 0
----

四、GenericDeclaration与TypeVariable

    GenericDeclaration是所有带有类型参数的实体的基类,声明很简单。只有一个方法,用来获取尖括号中的占位符信息:

public interface GenericDeclaration extends AnnotatedElement {

    //得到其中所有占位符
    public TypeVariable<?>[] getTypeParameters();
}

    TypeVariable就是泛型类中的参数列表,也就是类型后面尖括号中的内容。声明如下:

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
    //得到占位符边界,例如E extends xxx中的xxx
    Type[] getBounds();

    //得到占位符所属于的泛型类型
    D getGenericDeclaration();

    //得到占位符的名称,通常是K,V这样的
    String getName();

    //抱歉,没有搞清楚
    AnnotatedType[] getAnnotatedBounds();
}

    示例代码:

public class GenericDeclarationTest {
    public static void main(String[] argv) {
        GenericDeclaration clz = Generic.class;
        TypeVariable[] typeVariables = clz.getTypeParameters();

        int i = 1;
        for (TypeVariable tv : typeVariables) {
            System.out.println("variableNo: " + i++);
            System.out.println("getName: " + tv.getName());

            System.out.print("getBounds: ");
            for (Type t : tv.getBounds()) {
                System.out.print(t + ",");
            }
            System.out.println("");

            System.out.println("getGenericDeclaration: " + tv.getGenericDeclaration());

            System.out.print("getAnnotatedBounds: ");
            for (AnnotatedType at : tv.getAnnotatedBounds()) {
                System.out.print(at + ",");
            }
            System.out.println("");

            System.out.println("");
        }
    }
}

class Generic<K extends Integer, V extends List> {

}

    执行结果:

variableNo: 1
getName: K
getBounds: class java.lang.Integer,
getGenericDeclaration: class my.reflect.Generic
getAnnotatedBounds: sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@1540e19d,

variableNo: 2
getName: V
getBounds: interface java.util.List,
getGenericDeclaration: class my.reflect.Generic
getAnnotatedBounds: sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@677327b6,

 

五、AnnotatedType及其子类

 

 

 

六、Field与Executable及其子类

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值