泛型和泛型的反射

泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。如:ArrayList可以存放任意类型的对象,正是因为泛型的作用

泛型类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Pair<T> {

private T first;
private T second;

public T getFirst() {
return first;
}

public void setFirst(T first) {
this.first = first;
}

public T getSecond() {
return second;
}

public void setSecond(T second) {
this.second = second;
}
}

泛型方法

在一个普通类里边,定义一个泛型方法

1
2
3
4
5
6
7
public class GenericMethod {

public <T> T test(T name) {
System.out.println(name);
return name;
}
}

泛型变量的限定

有时候,类或方法需要对类型变量加以约束。

  1. <? extend T>表示限定泛型只能为T类型的子类或者T类型本身,也称为子类型限定
  2. <? super T> 表示限定泛型只能为T类型的父类或者T类型本身,也称为超类型限定

泛型代码和虚拟机

虚拟机中没有泛型类型对象,所有对象都属于普通类。

类型擦除

由于虚拟机中存在的都是普通类,因此无论何时定义一个泛型类型,都自动提供了一个相应的原始类型。原始类型就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定类型用Object)

桥方法

当一个泛型类作为另一个类的超类时,在子类中进行override泛型类的方法时,由于类型擦除的存在,将导致存在两个方法名相同,而入参不同的方法(从超类继承的方法入参为Object类型)。如以下代码中,DateInterval则存在一个桥方法setSecond(Object obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Pair<T> {

private T first;
private T second;

public T getFirst() {
return first;
}

public void setFirst(T first) {
this.first = first;
}

public T getSecond() {
return second;
}

public void setSecond(T second) {
this.second = second;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class DateInterval extends Pair<LocalDate> {

@Override
public void setSecond(LocalDate second) {
super.setSecond(second);
}

// 该方法由编译器生成
public void setSecond(Object obj) {
setSecond((LocalDate)obj);
}

}

反射和泛型

虽然在JVM中泛型类型被擦除,但是擦除的类仍然保留一些泛型祖先的记忆。我们可以通过反射API获得一些信息。为了表达泛型类型声明,使用java.lang.reflect包中提供的接口Type。
Type是所有类型的父接口,其类图如下

  1. Class类,描述具体类型
  2. TypeVariable接口,描述类型变量(如T extend Comparable<? super T>)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class TypeVariableTest<K extends Comparable & Serializable, V> {
    K key;
    V value;

    public static void main(String[] args) throws Exception{
    Field fk = TypeVariableTest.class.getDeclaredField("key");
    Field fv = TypeVariableTest.class.getDeclaredField("value");

    Assert.assertTrue("必须为TypeVariable类型", fk.getGenericType() instanceof TypeVariable);
    Assert.assertTrue("必须为TypeVariable类型", fv.getGenericType() instanceof TypeVariable);

    TypeVariable keyType = (TypeVariable) fk.getGenericType();
    TypeVariable valueType = (TypeVariable) fv.getGenericType();

    System.out.println(keyType.getName());
    System.out.println(valueType.getName());

    System.out.println(keyType.getGenericDeclaration());
    System.out.println(valueType.getGenericDeclaration());

    // 获取K上界
    for (Type type : keyType.getBounds()) {
    System.out.println(type);
    }
    // 获取V上界
    for (Type type : valueType.getBounds()) {
    System.out.println(type);
    }

    System.out.println("=====");
    // 获取类的类型参数。即K和V
    Type[] types = TypeVariableTest.class.getTypeParameters();
    for (Type type : types) {
    System.out.println(type instanceof ParameterizedType);
    }
    }
    }
  3. WildcardType接口,描述通配符(如? super T)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    public class WildcardTypeTest {

    private List<? extends Number> a;
    private List<? super String> b;
    private List<?> c;

    public static void main(String[] args) throws Exception {
    Field fieldA = WildcardTypeTest.class.getDeclaredField("a");
    Field fieldB = WildcardTypeTest.class.getDeclaredField("b");
    Field fieldC = WildcardTypeTest.class.getDeclaredField("c");

    Assert.assertTrue("", fieldA.getGenericType() instanceof ParameterizedType);
    Assert.assertTrue("", fieldB.getGenericType() instanceof ParameterizedType);
    Assert.assertTrue("", fieldC.getGenericType() instanceof ParameterizedType);

    ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
    ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
    ParameterizedType pTypeC = (ParameterizedType) fieldC.getGenericType();

    Assert.assertTrue("", pTypeA.getActualTypeArguments()[0] instanceof WildcardType);
    Assert.assertTrue("", pTypeB.getActualTypeArguments()[0] instanceof WildcardType);
    Assert.assertTrue("", pTypeC.getActualTypeArguments()[0] instanceof WildcardType);

    WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
    WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
    WildcardType wTypeC = (WildcardType) pTypeC.getActualTypeArguments()[0];

    // ? extend Number表明List所有存储的元素都是Number的子类,无法确定该List的下限限定
    for (Type lowerBound : wTypeA.getLowerBounds()) {
    System.out.println(lowerBound);
    }

    // ? super String,表明所有存储的元素都是String的父类,可以确定该List的下限为String
    for (Type lowerBound : wTypeB.getLowerBounds()) {
    System.out.println(lowerBound);
    }

    // ? extend Number表明List所有存储的元素都是Number的子类,可以确定该List的上限为Number
    for (Type upperBound : wTypeA.getUpperBounds()) {
    System.out.println(upperBound);
    }

    // ? super String表明List所有存储的元素都是String的超类,可以确定该List的上限为Object
    for (Type upperBound : wTypeB.getUpperBounds()) {
    System.out.println(upperBound);
    }

    System.out.println("========");
    System.out.println(wTypeC.getTypeName());
    for (Type upperBound : wTypeC.getUpperBounds()) {
    System.out.println(upperBound);
    }
    // 没有下限
    for (Type lowerBound : wTypeC.getLowerBounds()) {
    System.out.println(lowerBound);
    }
    }

    }
  4. ParameterizedType接口,描述泛型类或接口类型(如Comparable<? super T>)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class ParameterizedTypeTest {

    Map<String, Integer> map;

    public static void main(String[] args) throws NoSuchFieldException {
    Field f = ParameterizedTypeTest.class.getDeclaredField("map");

    System.out.println(f.getGenericType()); // 获得该字段的泛型定义 java.util.Map<java.lang.String, java.lang.Integer>
    System.out.println(f.getGenericType() instanceof ParameterizedType);

    ParameterizedType pType = (ParameterizedType) f.getGenericType(); // 字段map的泛型定义为"参数化类型"
    System.out.println(pType.getRawType()); // 参数化类型的原始类型 interface java.util.Map
    for (Type t : pType.getActualTypeArguments()) { // 参数化类型的实际类型,分别是class java.lang.String和class java.lang.Integer
    System.out.println(t);
    }

    }

    }
  5. GenericArrayType接口,描述泛型数组(如T[])

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class GenericArrayTypeTest {

    public static void main(String[] args) {
    Method method = Test.class.getDeclaredMethods()[0];

    System.out.println(method);
    Type[] types = method.getGenericParameterTypes();
    Class<?>[] parameterTypes = method.getParameterTypes();

    for (Type type : types) {
    System.out.println(type instanceof GenericArrayType);
    }

    for (Class<?> parameterType : parameterTypes) {
    System.out.println(parameterType);
    }
    }

    }

    class Test<T> {
    public void show(List<String>[] pTypeArray, T[] vTypeArray, List<String> list, String[] strings, int[] ints, String s){}
    }

反射和泛型的应用

  1. 可以利用泛型和反射API来实现通用的DAO类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    // 定义一个泛型的通用DAO接口
    public interface BaseDAO<T, PK> {

    T selectByPrimaryKey(PK id);

    void add(T t);

    void update(T t);

    void delete(T t);

    }

    // 实现一个通用的DAO,利用反射的机制,获取DAO处理的实体类
    public class BaseDAOImpl<T, PK> implements BaseDAO<T, PK> {

    private Class<T> entityClazz;

    public BaseDAOImpl() {
    // getClass()获取到的是子类的Class对象,因为getClass() -> this.getClass() 即调用了子类的getClass()
    ParameterizedType pType = (ParameterizedType) getClass().getGenericSuperclass();
    entityClazz = (Class<T>) pType.getActualTypeArguments()[0];
    }

    @Override
    public T selectByPrimaryKey(PK id) {
    System.out.println(entityClazz.getName() + " selectByPrimaryKey");
    return null;
    }

    @Override
    public void add(T t) {
    System.out.println(entityClazz.getName() + " add");
    }

    @Override
    public void update(T t) {
    System.out.println(entityClazz.getName() + " update");
    }

    @Override
    public void delete(T t) {
    System.out.println(entityClazz.getName() + " delete");
    }
    }

    // 定义一个处理具体实体类的DAO接口
    public interface UserDAO extends BaseDAO<User, Integer> {

    // 1. 该接口默认继承了BaseDAO的功能接口
    // 2. 可以定义扩展的其他DAO方法
    }

    // 实现处理具体实体类的DAO
    public class UserDAOImpl extends BaseDAOImpl<User, Integer> implements UserDAO {
    // 此时UserDAOImpl拥有了在BaseDAOImpl中实现的基础功能(增删改查)
    }
  2. mybatis中的org.apache.ibatis.reflection.Reflector解析类