Java中的类型(Type)体系的一些思考

231 阅读4分钟

Java中的类型(Type)体系的一些思考

Java 编程语言从Java 5以后就引入Type体系,应该是为了加入泛型而引入的。

Java Type 体系,始于Type接口,其是Java编程语言中所有类型的父接口,是对Java编程语言类型的一个抽象,源码如下所示:

public interface Type {
    //返回这个类型的描述,包括此类型的参数描述。
    default String getTypeName() {
        return toString();
    }
}

子接口:

  • TypeVariable - 类型变量
  • Parameterizedtype - 参数化类型
  • GenericArrayType - 数组类型
  • WildcardType - 通配符类型

实现类:

  • Class

AnnotatedType.png

TypeVariable

类型变量,例如List<T>中的T, Map<K,V>中的KV,再比如类class TypeTest<T, V extends Object & Serializable>中的TV

此接口源码如下:

interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
  
    //返回此类型参数的上界列表,如果没有上界则放回Object. 
    //例如  V extends Object & Serializable 这个类型参数,有两个上界,Object 和 Serializable 
    Type[] getBounds();
  
    //类型参数声明时的载体
    //例如 `class TypeTest<T, V extends Object & Serializable>` ,那么V 的载体就是TypeTest
    D getGenericDeclaration();
  
    String getName();
  
    //Java 1.8加入 AnnotatedType
    //如果这个这个泛型参数类型的上界用注解标记了,我们可以通过它拿到相应的注解
    AnnotatedType[] getAnnotatedBounds();
}

测试代码:

public class TypeVariableDemo {
​
    @Deprecated
    abstract class A<K extends String & Serializable, V extends Object & Serializable> implements Map<K, V> {}
​
    public static void main(String[] args) {
        TypeVariable<Class<A>>[] typeParameters = A.class.getTypeParameters();
        assert 2 == typeParameters.length;
        // name0 是 K,上界是:String 和 Serializable
        String name0 = typeParameters[0].getName();
        assert "K".equals(name0);
        Type[] bound0s = typeParameters[0].getBounds();
        assert "String".equals(bound0s[0].getTypeName());
        assert "Serializable".equals(bound0s[1].getTypeName());
        // name0 的载体(genericDeclaration)是 A.class
        assert TypeVariableDemo.A.class.equals(typeParameters[0].getGenericDeclaration());
        // name0 绑定注解是 @Deprecated
        assert Deprecated.class.equals(typeParameters[0].getBounds()[0]);
​
        // name1 是 V,上界是:Object 和 Serializable
        String name1 = typeParameters[0].getName();
        assert "V".equals(name1);
        Type[] bound1s = typeParameters[1].getBounds();
        assert "Object".equals(bound1s[0].getTypeName());
        assert "Serializable".equals(bound1s[1].getTypeName());
        // name1 的载体(genericDeclaration)是 A.class
        assert TypeVariableDemo.A.class.equals(typeParameters[1].getGenericDeclaration());
        // name1 绑定注解是 @Deprecated
        assert Deprecated.class.equals(typeParameters[1].getBounds()[0]);
​
    }
​
}

ParameterizedType

参数化类型,即带参数的类型,也可以说带<>的类型。例如List<String>, User<T> 等。

其源码如下:

interface ParameterizedType extends Type {
  
     // 获取参数类型<>里面的那些值
     // 例如Map<K,V> 那么就得到[K,V]的一个数组
     Type[] getActualTypeArguments(); 
  
     // 获取参数类型<>前面的值
     // 例如例如Map<K,V> 那么就得到 Map
     Type getRawType();
  
     // 获取内部类所在类的类型
     // 例如Map有一个内部类Entry, 那么在Map.Entry<K,V>上调用这个方法就可以获得Map
     Type getOwnerType();
}

测试代码:

public class ParameterizedTypeDemo {
​
    interface A<K extends String, V extends Object> extends Map<K, V> {
        abstract class AEntity<K extends String, V extends Object> implements Map.Entry<K, V> {}
    }
​
    abstract class ChildA<K extends String, V extends Object> implements A<K, V>, Map<K, V> {}
​
    public static void main(String[] args) {
        List<ParameterizedType> parameterizedTypes = Arrays.stream(A.class.getGenericInterfaces())
                .filter(type -> type instanceof ParameterizedType)
                .map(ParameterizedType.class::cast)
                .collect(Collectors.toList());
        // parameterizedTypes --> [Map]
        assert 1 == parameterizedTypes.size();
        Type ownerType0 = parameterizedTypes.get(0).getOwnerType();
        assert ownerType0 == null;
        Type rawType0 = parameterizedTypes.get(0).getRawType();
        assert Map.class.equals(rawType0);
        Type[] actualTypeArguments0 = parameterizedTypes.get(0).getActualTypeArguments();
        assert "K".equals(actualTypeArguments0[0].getTypeName());
        assert "V".equals(actualTypeArguments0[1].getTypeName());
​
        List<ParameterizedType> parameterizedTypes1 = Arrays.stream(A.AEntity.class.getGenericInterfaces())
                .filter(type -> type instanceof ParameterizedType)
                .map(ParameterizedType.class::cast)
                .collect(Collectors.toList());
        // parameterizedTypes --> [Map.Entry]
        assert 1 == parameterizedTypes1.size();
        Type ownerType1 = parameterizedTypes1.get(0).getOwnerType();
        // 内部类所在类是 Map
        assert Map.class.equals(ownerType1);
        Type rawType1 = parameterizedTypes1.get(0).getRawType();
        assert Map.Entry.class.equals(rawType1);
        Type[] actualTypeArguments1 = parameterizedTypes1.get(0).getActualTypeArguments();
        assert "K".equals(actualTypeArguments1[0].getTypeName());
        assert "V".equals(actualTypeArguments1[1].getTypeName());
​
        List<ParameterizedType> parameterizedTypes2 = Arrays.stream(ChildA.class.getGenericInterfaces())
                .filter(type -> type instanceof ParameterizedType)
                .map(ParameterizedType.class::cast)
                .collect(Collectors.toList());
        // parameterizedTypes --> [A, Map]
        assert 2 == parameterizedTypes2.size();
        assert A.class.equals(parameterizedTypes2.get(0).getOwnerType());
        assert Map.class.equals(parameterizedTypes2.get(1).getOwnerType());
    }
​
}

GenericArrayType

泛型数组类型,用来作为数组的泛型声明类型。例如List<T>[] ltArrayT[] tArray两个数组,其中List<T>[], 和T[]就是GenericArrayType类型。

此接口的源码如下:

public interface GenericArrayType extends Type {
  
    //获取泛型类型数组的声明类型,即获取数组方括号 [] 前面的部分
    Type getGenericComponentType();
}

GenericArrayType 接口只有一个方法getGenericComponentType(),其可以用来获取数组方括号 [] 前面的部分,例如T[],在其上调用getGenericComponentType 就可以获得T. 值得注意的是多维数组得到的是最后一个[] 前面的部分,例如T[][], 得到的是T[].

测试代码:

public class GenericArrayTypeDemo {
​
    public <T> T[] demo() {
        return null;
    }
​
    public static void main(String[] args) {
        Method[] declaredMethods = GenericArrayTypeDemo.class.getDeclaredMethods();
        Method demo = Arrays.stream(declaredMethods).filter(x -> x.getName().equals("demo")).findFirst().orElse(null);
        Type returnType = demo.getGenericReturnType();
        assert GenericArrayType.class.equals(returnType.getClass());
        GenericArrayType aClass = (GenericArrayType) returnType;
        Type type = aClass.getGenericComponentType();
        assert "T".equals(type.getTypeName());
    }
​
}

WildcardType

通配符类型,即带有?的泛型参数, 例如 List<?>中的List<? extends Number>里的? extends NumberList<? super Integer>? super Integer

此接口源码如下:

public interface WildcardType extends Type {
  
   // 获取上界
    Type[] getUpperBounds();
  
    //获取下界
    Type[] getLowerBounds();
}

测试代码:

public class WildcardTypeDemo {
​
    public Class<? extends Object> demo() {
        return null;
    }
​
    public static void main(String[] args) {
        Method[] declaredMethods = WildcardTypeDemo.class.getDeclaredMethods();
        Method demo = Arrays.stream(declaredMethods).filter(x -> x.getName().equals("demo")).findFirst().orElse(null);
​
        Type returnType = demo.getGenericReturnType();
        ParameterizedType parameterizedType = (ParameterizedType) returnType;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        Type returnArgType0 = actualTypeArguments[0];
        WildcardType returnArgWildcardType0 = (WildcardType) returnArgType0;
        // upperBounds --> Object
        Type[] upperBounds = returnArgWildcardType0.getUpperBounds();
        assert Object.class.equals(upperBounds[0]);
    }
​
}

Class

其是Type的一个实现类,是反射的基础,每一个类在虚拟机中都对应一个Calss 对象,我们可以用在运行时从这个Class对象中获取到类型所有信息。

其他

代码地址:lumm/lumm-java/lumm-java-type at main · jjzBruce/lumm