范型是这样的-1

前一阵在做一个功能的时候,要通过反射去取List的范型定义,所以研究了一下java范型的整个模型,现在总结一下,免得以后忘掉。

大家都说Java范型是编译器层面的实现,运行时拿不到范型类。就这句话,我的理解就是,通过对象实例,你是拿不到其范型相关信息,而记录在字节码里的,也就是类上的,方法上的,类变量上的还是可以拿到的。比如某个类中的代码
//这里Alist的超类限制了是只能放String的范型
//这个范型信息可以通过Alist.class来获取
public class AList extends ArrayList<String> {

    public void Test() {
        //这个list实例的范型定义应该是只能放String
        //但这个信息是仅仅依靠list这个实例引用是取不到的
        List<String> list = new ArrayList<String>()
    }

}


java范型的根对象是java.lang.reflect.Type接口该接口没有任何方法,仅仅是一个标志性的接口,所有的范型信息(也就是<>中定义的东西)都是可以上溯到该接口。


该接口下有四类子接口和一实现类,实现类就是Class类,而接口包括:
GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType
妈的,这几个名字可够拗口的。其中TypeVariable<D>和其他三种接口类型有一定的明显区别,虽然他们都是用来定义<>中的东东。


说到TypeVariable<D>就不得不提起java范型中另一个比较重要的接口对象,java.lang.reflect.GenericDeclaration接口对象。该接口用来定义哪些对象上是可以声明范型变量,所谓范型变量就是<E extends List>或者<E>, 也就是TypeVariable<D>这个接口的对应的对象,TypeVariable<D>中的D是extends GenericDeclaration的,用来通过范型变量反向获取拥有这个变量的GenericDeclaration

目前实现GenericDeclaration接口的类包括Class, Method, Constructor,也就是只能在这几种对象上进行范型变量的声明。GenericDeclaration的接口方法getTypeParameters用来逐个获取该GenericDeclaration的范型变量声明。
比如:
public class ClassA <K extends List & Serializable, V> {

}


类ClassA上就有两个TypeVariable<D>可以通过ClassA.class.getTypeParameters()[0]来获取第一个范型变量"K extends List"的信息。从而更进一步拿到变量名字,变量上界,变量所在的GenericDeclaration对象。

//获取范型变量定义
TypeVariable t = ClassA.class.getTypeParameters()[0];
t.getName();//获取变量名字,返回K
t.getGenericDeclaration();//获取变量被定义在什么GenericDeclaration上,这里返回ClassA.class
t.getBounds()[0];//变量上边界数组,这里返回List.class
t.getBounds()[1];//变量上边界数组,这里返回Serializable.class

//当然可以获取第二个变量定义
t = ClassA.class.getTypeParameters()[1];
t.getName();//返回V
t.getGenericDeclaration();//获取变量被定义在什么GenericDeclaration上,这里返回ClassA.class
t.getBounds()[0];//变量上边界数组,这里返回Object.class,并且上边界只有一个

你可能感兴趣的:(java)