Java Type与Generic
Type 是什么
Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types.
这个Type接口是在1.5后才被引入的,子类有GenericArrayType、ParameterizedType、WildcardType、TypeVaribale,在1.5之前,没有这个Type,全部都是Class,引入的主要原因是由于泛型的引入,其他的子类除了Class都是在1.5的时候一起引入的。
Class
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
在没有泛型之前,java中的所有的类(包括枚举)、接口(包括注解)、原生的数据类型都是class。
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
所有的类对象都是类加载器加载的。
System.out.println(String.class.getName()); // java.lang.String
System.out.println(int.class.getName()); // int
System.out.println(Runnable.class.getName()); // java.lang.Runnable
System.out.println(Nullable.class.getName()); // 注解 com.sun.istack.internal.Nullable
System.out.println(String.class instanceof Type); // true
ParameterizedType
ParameterizedType represents a parameterized type such as Collection
. A parameterized type is created the first time it is needed by a reflective method, as specified in this package. When a parameterized type p is created, the generic type declaration that p instantiates is resolved, and all type arguments of p are created recursively. See TypeVariable for details on the creation process for type variables. Repeated creation of a parameterized type has no effect.
指具体的泛型类型,参数化的类型,参数就是指下面的TypeVariable。注意,这里Parameterized这个修饰,在java中也可以定义Map m;这样的map(不推荐,参考Effective Java中的请不要在新代码中使用原生态类型row type),这类型没有参数,也不是ParameterizedType。
public class TestType {
Map<String, String> map;
Map mapNoPara;
public static void main(String[] args) throws Exception {
Field f = TestType.class.getDeclaredField("map");
System.out.println(f.getGenericType()); // java.util.Map<java.lang.String, java.lang.String>
System.out.println(f.getGenericType() instanceof ParameterizedType); // true
ParameterizedType pType = (ParameterizedType) f.getGenericType();
System.out.println(pType.getRawType()); // interface java.util.Map
for (Type type : pType.getActualTypeArguments()) {
System.out.println(type); // 打印两遍: class java.lang.String
}
Field f2 = TestType.class.getDeclaredField("mapNoPara");
System.out.println(f2.getGenericType() instanceof ParameterizedType); // false
}
}
TypeVariable
TypeVariable is the common superinterface for type variables of kinds. A type variable is created the first time it is needed by a reflective method, as specified in this package. If a type variable t is referenced by a type (i.e, class, interface or annotation type) T, and T is declared by the nth enclosing class of T (see JLS 8.1.2), then the creation of t requires the resolution (see JVMS 5) of the ith enclosing class of T, for i = 0 to n, inclusive. Creating a type variable must not cause the creation of its bounds. Repeated creation of a type variable has no effect.
可以理解为泛型中的T、E这些,这个类型里面有该类型bounds。
public class TestType <K extends Comparable & Serializable, V> {
K key;
V value;
public static void main(String[] args) throws Exception {
// 获取字段的类型
Field fk = TestType.class.getDeclaredField("key");
Field fv = TestType.class.getDeclaredField("value");
System.out.println( "TypeVariable类型" + (fk.getGenericType() instanceof TypeVariable)); // true
System.out.println( "TypeVariable类型" + (fv.getGenericType() instanceof TypeVariable)); // true
TypeVariable keyType = (TypeVariable)fk.getGenericType();
TypeVariable valueType = (TypeVariable)fv.getGenericType();
// getName 方法
System.out.println(keyType.getName()); // K
System.out.println(valueType.getName()); // V
// getGenericDeclaration 方法
System.out.println(keyType.getGenericDeclaration()); // class com.test.TestType
System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
// getBounds 方法
System.out.println("K 的上界:"); // 有两个
for (Type type : keyType.getBounds()) { // interface java.lang.Comparable
System.out.println(type); // interface java.io.Serializable
}
System.out.println("V 的上界:"); // 没明确声明上界的, 默认上界是 Object
for (Type type : valueType.getBounds()) { // class java.lang.Object
System.out.println(type);
}
}
}
GenericArrayType
GenericArrayType represents an array type whose component type is either a parameterized type or a type variable.
泛型数组类型,类型中有泛型,还必须是数组
public static void main(String[] args) throws Exception {
Method method = Test.class.getDeclaredMethods()[0];
// public void com.test.Test.show(java.util.List[],java.lang.Object[],java.util.List,java.lang.String[],int[])
System.out.println(method);
Type[] types = method.getGenericParameterTypes();
for (Type type : types) {
System.out.println(type instanceof GenericArrayType);
}
}
class Test<T> {
public void show(List<String>[] pTypeArray, // List<String>是ParameterizedType类型 true
T[] vTypeArray, // T是TypeVariable类型,true
List<String> list,
String[] strings, // String是普通对象, 没有范型,false
int[] ints) {
}
}
WildcardType
WildcardType represents a wildcard type expression, such as ?, ? extends Number, or ? super Integer. 该接口表示通配符泛型, 比如? extends Number 和 ? super Integer
public class TestType {
private List<? extends Number> a; // // a没有下界, 取下界会抛出ArrayIndexOutOfBoundsException
private List<? super String> b;
public static void main(String[] args) throws Exception {
Field fieldA = TestType.class.getDeclaredField("a");
Field fieldB = TestType.class.getDeclaredField("b");
// 先拿到范型类型
System.out.println(fieldA.getGenericType() instanceof ParameterizedType); // true
System.out.println(fieldB.getGenericType() instanceof ParameterizedType); // true
ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
// 再从范型里拿到通配符类型
System.out.println(pTypeA.getActualTypeArguments()[0] instanceof WildcardType); // true
System.out.println(pTypeB.getActualTypeArguments()[0] instanceof WildcardType); // true
WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
// 方法测试
System.out.println(wTypeA.getUpperBounds()[0]); // class java.lang.Number
System.out.println(wTypeB.getLowerBounds()[0]); // class java.lang.String
// 看看通配符类型到底是什么, 打印结果为: ? extends java.lang.Number
System.out.println(wTypeA);
}
}
Generic
在没有泛型之前,从集合中读取每一个元素都需要进行转换,而且插入的时候也没有任何限制,很容易就插入了类型不一致的元素到同一个集合中。有了泛型后,编译器就能在插入时候进行转化,并且给出错误的提示。
对于List
原生态类型List与List
其实泛型解决的一个主要问题就是类型检查,这两个区别也一样,对于一个List
public static void main(String[] args) throws Exception {
String s = "";
System.out.println(s instanceof Object); // true
List<String> strList = new ArrayList<>();
List<Object> objList = new ArrayList<>();
System.out.println(strList instanceof List); // true
List rawList = strList;
objList = strList; // 编译报错,编译器会进行类型检查
System.out.println(strList instanceof List<Object>); // 编译报错
}
System.out.println(strList instanceof List
无限制通配符List<?> 与List有什么区别?
首先,由于上面说的List
那List<?>与List还有什么区别?还是类型检查上,不能将任何元素(null除外)放到List<?>中,这样就保证了类型的安全。
那么List这种原生类型的对象还有什么用?这原生类型的对象使用如List list这样的,只是为了向前兼容。
列表优于数组
这是Effective Java上的条目,有两个原因:
- 数组是协变的(covariant),如果sub为super的子类型,那么数组类型sub[]就是super[]的子类型
- 数组是具体化的(reified),数组在运行时才检查类型约束,而泛型是在编译时候检查,运行时候擦除
public static void main(String[] args) throws Exception {
Object[] objects = new Object[1];
String[] strings = new String[1];
List<Object> objectList = new ArrayList<>();
System.out.println(Object.class); // class java.lang.Object
System.out.println(objectList.getClass()); // class java.util.ArrayList
System.out.println(objects.getClass()); // class [Ljava.lang.Object
System.out.println(strings instanceof Object[]); // true
}
List
由上面两点,可以推出,不能有泛型数组。因为通过数组这协变的特性,能够把不同类型的泛型进行赋值。书中作者说的“数组是由缺陷的”,代码如下,和使用原始类型的List,没有泛型的容器一样,一个数组中有多种不同的类型的对象。
public static void main(String[] args) throws Exception {
Object[] objects = new Object[2];
String[] strings = new String[1];
Integer[] integers = new Integer[1];
objects[0] = strings[0];
objects[1] = integers[1];
}
Spirng Type
从上面的Demo中看到,一些类型的操作还是比较麻烦的,Spring中提供了一些相关的工具类,如GenericTypeResolver,并且对于Java的类型进行了一些封装,很多源码中有ResolvableType这类型的使用。本质上只是个封装的,使用比较容易的类,并没有对Type进行功能扩展,doc上的demo:
private HashMap<Integer, List<String>> myMap;
public void example() {
ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
t.getSuperType(); // AbstractMap<Integer, List<String>>
t.asMap(); // Map<Integer, List<String>>
t.getGeneric(0).resolve(); // Integer
t.getGeneric(1).resolve(); // List
t.getGeneric(1); // List<String>
t.resolveGeneric(1, 0); // String
}