Java反射中的Type类型

2,532 阅读3分钟

Java进阶笔记,参照(实则CV)大佬的blog,给大佬👍。 loveshisong.cn/%E7%BC%96%E…

Type类型

Type类型是所有类型的通用父接口,主要包括原始类型,参数化类型,数组类型,类型变量和基本类型。

原始类型(raw types)Class
参数化类型(parameterized types)ParameterizedType
数组类型(array types)GenericArrayType
类型变量(type variables)TypeVariable
基本类型(primitive types)Class

ParameterizedType

具体的范型类型,如Map<String, String> 有如下方法:

  1. Type getRawType():返回承载该泛型信息的对象,如上面那个Map承载范型信息的对象是Map
  2. Type[] getActualTypeArguments():返回实际泛型类型列表,如上面那个Map实际范型列表中有两个元素,都是String
  3. Type getOwnerType(): 返回是谁的member。(上面那两个最常用)
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

public class TestType {
    Map<String, String> map;
    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
        }
        System.out.println(pType.getOwnerType());                             // null
    }
}

TypeVariable

范型信息在编译时会被转换为一个特定的类型,而TypeVariable就是反映jvm在编译该范型前的信息。

  1. Type[] getBounds():获取类型变量的上边界, 若未明确声明上边界则默认为Object
  2. D getGenericDeclaration():获取声明该类型变量实体。
  3. String getName():获取在源码中定义时的名字。

注意:

  • 类型变量在定义的时候只能使用extends进行(多)边界限定, 不能用super

为什么边界是一个数组? 因为类型变量可以通过&进行多个上边界限定,因此上边界有多个。

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

import sun.jvm.hotspot.utilities.Assert;

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");
        Assert.that(fk.getGenericType() instanceof TypeVariable, "必须为TypeVariable类型");
        Assert.that(fv.getGenericType() instanceof TypeVariable, "必须为TypeVariable类型");
        TypeVariable keyType = (TypeVariable)fk.getGenericType();
        TypeVariable valueType = (TypeVariable)fv.getGenericType();
        // getName 方法
        System.out.println("getName 方法:");
        System.out.println(keyType.getName()); // K
        System.out.println(valueType.getName()); // V
        // getGenericDeclaration 方法
        System.out.println("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

范型数组,组成数组的元素中有范型则实现了该接口,它的组成元素是ParameterizedTypeTypeVariable类型,它只有一个方法:

Type getGenericComponentType();

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;

public class TestType<T> {
    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(); // 这是 Method 中的方法
        for (Type type : types) {
            System.out.println(type + " -- " + (type instanceof GenericArrayType));
        }
    }
}

class Test<T> {
    public void show(List<String>[] pTypeArray, T[] vTypeArray, List<String> list, String[] strings,
        int[] ints) {}
}
  • 第一个参数List[]的组成元素ListParameterizedType类型, 打印结果为true
  • 第二个参数T[]的组成元素TTypeVariable类型, 打印结果为true
  • 第三个参数List不是数组, 打印结果为false
  • 第四个参数String[]的组成元素String是普通对象, 没有范型, 打印结果为false
  • 第五个参数int[] pTypeArray的组成元素int是原生类型, 也没有范型, 打印结果为false

WildcardType

该接口表示通配符泛型, 比如? extends Number? super Integer 它有如下方法:

  1. Type[] getUpperBounds(): 获取范型变量的上界
  2. Type[] getLowerBounds(): 获取范型变量的下界

注意:

  • 现阶段通配符只接受一个上边界或下边界, 返回数组是为了以后的扩展, 实际上现在返回的数组的大小是1
import sun.jvm.hotspot.utilities.Assert;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.WildcardType;
import java.util.List;

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");
        // 先拿到范型类型
        Assert.that(fieldA.getGenericType() instanceof ParameterizedType, "");
        Assert.that(fieldB.getGenericType() instanceof ParameterizedType, "");
        ParameterizedType pTypeA = (ParameterizedType)fieldA.getGenericType();
        ParameterizedType pTypeB = (ParameterizedType)fieldB.getGenericType();
        // 再从范型里拿到通配符类型
        Assert.that(pTypeA.getActualTypeArguments()[0] instanceof WildcardType, "");
        Assert.that(pTypeB.getActualTypeArguments()[0] instanceof WildcardType, "");
        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);
    }
}

再写几个边界的例子:

  • List, 上界为class java.lang.Number, 属于Class类型
  • List>, 上界为java.util.List, 属于ParameterizedType类型
  • List>, 上界为java.util.List, 属于ParameterizedType类型
  • List, 上界为T, 属于TypeVariable类型
  • List, 上界为T[], 属于GenericArrayType类型

它们最终统一成Type作为数组的元素类型