Java泛型

1. 泛型擦除

泛型是在 Jdk1.5 之后引入的,为了使字节码向前兼容,Java编译器会在编译时擦除泛型信息(泛型擦除)。假使有泛型类Xx<T>,对其进行反射并打印类中的泛型方法:

public class Xx<T> {
    public void m(T t) {}
    public void m(T[] arr) {}
    public void m(List<T> list) {}
}
Method[] declaredMethods = Xx.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println(declaredMethod);
}

打印信息如下:

public void Xx.m(java.util.List)
public void Xx.m(java.lang.Object[])
public void Xx.m(java.lang.Object)

2. 桥接方法

假使有类Xx2继承自Xx<String>,则显然Xx2并未覆盖Xx中的两个方法:

1. public void Xx.m(java.lang.Object)

2. public void Xx.m(java.lang.Object[])

public class Xx2 extends Xx<String> {
    @Override
    public void m(String t) {}
    @Override
    public void m(String[] arr) {}
    @Override
    public void m(List<String> list) {}
}

对Xx2进行反射并打印类中的方法:

Method[] declaredMethods = Xx2.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println(declaredMethod);
}
public void Xx2.m(java.util.List)
public void Xx2.m(java.lang.Object[])
public void Xx2.m(java.lang.Object)
public void Xx2.m(java.lang.String[])
public void Xx2.m(java.lang.String)

可见Xx2源码被编译成字节码后,额外生成了两个方法:

1. public void Xx2.m(java.lang.Object)

2. public void Xx2.m(java.lang.Object[])

这两个方法被称为桥接方法。桥接方法覆盖父类中的泛型方法,并在内部调用子类中的具体方法:

public void m(Object t) {
    m((String) t);
}
public void m(Object[] arr) {
    m((String[]) arr);
}

可以使用Method.isBridge来判断方法是否为桥接方法:

Method[] declaredMethods = Xx2.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println(declaredMethod);
    System.out.println("  -isBridge: " + declaredMethod.isBridge());
}
public void Xx2.m(java.util.List)
  -isBridge: false
public void Xx2.m(java.lang.Object[])
  -isBridge: true
public void Xx2.m(java.lang.Object)
  -isBridge: true
public void Xx2.m(java.lang.String[])
  -isBridge: false
public void Xx2.m(java.lang.String)
  -isBridge: false

3. 获取泛型信息

Java编译器会擦除方法内部的泛型信息:

void m() {
  List<String> list = new ArrayList<>();
}

因此,方法内部全部对象的泛型信息将丢失。但Java编译器也在字节码中保留三处泛型信息:

1. 类定义的泛型信息

2. 类中字段的泛型信息

3. 方法参数的泛型信息

Java泛型信息由java.lang.reflect.Type的五个子类进行描述:

1. java.lang.Class(如:java.lang.String)

2. java.lang.reflect.TypeVariable(如:T)

3. java.lang.reflect.WildcardType(如:? extends Comparable)

4. java.lang.reflect.GenericArrayType(如:T[])

5. java.lang.reflect.ParameterizedType(如:List<String>)

3.1 获取类定义上的泛型信息

1. Class.getTypeParameters

TypeVariable<Class<Xx>> typeParameter = Xx.class.getTypeParameters()[0];
System.out.println(typeParameter + ": " + typeParameter.getClass());

打印信息如下:

T: class sun.reflect.generics.reflectiveObjects.TypeVariableImpl

2. Class.getGenericSuperClass / Class.getGenericInterfaces

Type genericSuperclass = Xx2.class.getGenericSuperclass();
System.out.println(genericSuperclass + ": " + genericSuperclass.getClass());

打印信息如下:

Xx<java.lang.String>: class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl

3.2 类中字段的泛型信息(Field.getGenericType)

List<? extends String> list;
Field list = Xx.class.getDeclaredField("list");
Type genericType = list.getGenericType();
System.out.println(genericType + ": " + genericType.getClass());

打印信息如下:

java.util.List<? extends java.lang.String>: class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl

3.3 方法参数的泛型信息(Method.getGenericParameterTypes / Method.getGenericReturnType)

Method m = Xx.class.getDeclaredMethod("m", Object[].class);
Type parameterType = m.getGenericParameterTypes()[0];
System.out.println(parameterType + ": " + parameterType.getClass());

打印信息如下:

T[]: class sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl

 

posted @ 2018-01-15 17:58  Uncle_Bjorney  阅读(212)  评论(0)    收藏  举报