这几天看class类的代码,对泛型有了一点理解,在这里与大家分享一下。
首先我们来看一个非常简单的泛型
public class TestA<K extends List & Serilizable, V> {
...
}
在这个类中<K extends List & Serilizable, V>称为泛型变量。
而K extends List & Serilizable的意思是K这个泛型是有上界的,它必须是一个继承List以及Serilizable的类或接口。
说完这些我们在来看看class类,class类继承的和泛型有关的接口有GenericDecalaration以及Type。
GenericDecalaration接口是说明哪些类的对象可以通过反射机制来获取泛型声明,它有三个实现类,分别是Cass, Constructor, Method。
可能我们会奇怪为什么没有Object类,那是因为Object类有一个
public final native Class<?> getClass();方法。
通过调用这个方法我们可以返回一个Class类型的对象
以下面这个例子为例:
public class Test {
public static void main(String[] args) {
Test t = new Test();
Class<? extends Test> c = t.getClass();
System.out.println(c.getName()); //输出Test
}
}
我们定义了一个Test类,然后生成了一个实例化对象t,通过getClass方法我们获得了t的运行时类对象c,这个是c就是Class类型的。我们试图将它输出到控制台,显示的结果正好就是Test——我们自定义的类的名称。
所以说每一个Object类的子类都可以通过getClass来获得其对应的运行时类对象。Class类实现了GenericDecalaration接口就约等于所有Object的子类都实现了GenericDecalaration接口了。
那么实现GenericDecalaration接口有什么用呢?GenericDecalaration接口有一个
public TypeVariable<?>[] getTypeParameters();方法
这个方法返回的泛型变量数组代表了泛型声明的内容,TypeVariable类型就是定义泛型变量的。
以下面这个例子为例:
public class Test<K extends List & Serializable, V> {
public static void main(String[] args) {
Test t = new Test();
TypeVariable[] tvarg = t.getClass().getTypeParameters();
System.out.println("tvarg.lenght=" + tvarg.length); //tvarg.lenght=2
}
}
我们可以看到通过getTypeParameters方法返回了一个长度为2的数组,他们分别表示了
<K extends List & Serializable, V>
泛型变量中的
K和V(extends List & Serializable应该属于修饰)
从下面开始我们就要来分析一下泛型变量TypeVariable接口
TypeVariable总共有三个方法
Type[] getBounds();
D getGenericDeclaration();
String getName();
Type[] getBounds();方法很好理解,就是返回当前类型的边界,
以刚刚的例子为例K extends List & Serializable,那k的边界就应该是List和Serializable
用下面的例子来试验一下
public class Test<K extends List & Serializable, V> {
public static void main(String[] args) {
TypeVariable[] tvarg = new Test().getClass().getTypeParameters();
Type[] typearg = tvarg[0].getBounds();
System.out.println("typearg.lenght=" + typearg.length);
for (int i = 0; i < typearg.length; i++) {
System.out.println(typearg[i].toString());
}
}
}
我们看到控制台先输出了typearg.lenght=2说明有两个上边界。然后分别输出了两个边界的类型。
D getGenericDeclaration();方法则是返回在哪一个类上面进行了泛型的声明(我们看这个方法的名字直译是“获取通用声明”,但返回的却是一个在代码中具有声明的类的运行时类对象。我们可以这样理解,Class类型实现了GenericDeclaration接口,那我们要看声明的代码就要往这个Class上找,可以看成是一种提示吧。)
以下面的例子为例
public class Test<K extends List & Serializable, V> {
public static void main(String[] args) {
TypeVariable[] tvarg = new Test().getClass().getTypeParameters();
GenericDeclaration gd0 = tvarg[0].getGenericDeclaration();
GenericDeclaration gd1 = tvarg[1].getGenericDeclaration();
System.out.println("gd0=" + gd0.toString());
System.out.println("gd1=" + gd1.toString());
}
}
在控制台直接显示了这个泛型是声明在Test这个类。
最后String getName();方法返回的是泛型变量的名称,就一刚刚那个例子为例,然后的就是K和V
public class Test<K extends List & Serializable, V> {
public static void main(String[] args) {
TypeVariable[] tvarg = new Test().getClass().getTypeParameters();
System.out.println("tvarg0=" + tvarg[0].getName());
System.out.println("tvarg1=" + tvarg[1].getName());
}
}
通过这几个方法我们就可以利用反射机制来动态获取类型的泛型声明了。