【小家Java】你真的了解Java泛型参数吗?细说java.lang.reflect.Type(ParameterizedType、TypeVariable、WildcardType...)

每篇一句

不要每天看着励志的句子,过着颓废的生活

前言

咋一看标题,你可能会说。不就是泛型吗,平时都使用着呢,没什么难的吧。
感觉了解了,但是真正的深入才知道自己了解甚少!

没有泛型的时候,只有原始类型。此时,所有的原始类型都通过字节码文件类Class类进行抽象。Class类的一个具体对象就代表一个指定的原始类型
泛型出现之后,扩充了数据类型。从只有原始类型扩充了参数化类型、类型变量类型、限定符类型 、泛型数组类型

深入了解Java对类型的管理,对我们理解序列化、反序列化的深入理解讲非常有帮助。
类型的父类为Type,它位于反射包java.lang.reflect内。由JDK1.5之后提供的,它的标准继承图谱吐下:
在这里插入图片描述
(从左到右)依次是:GenericArrayType(数组类型)、ParameterizedType(参数化类型)、WildcardType( 泛型表达式类型)、TypeVariable(类型变量)、Class(原始/基本类型)

  • Class(原始/基本类型,也叫raw type):不仅仅包含我们平常所指的类、枚举、数组、注解,还包括基本类型int、float等等
  • TypeVariable(类型变量):比如List<T>中的T等
  • WildcardType( 泛型表达式类型):例如List< ? extends Number>这种
  • ParameterizedType(参数化类型):就是我们平常所用到的泛型List、Map(注意和TypeVariable的区别)
  • GenericArrayType(数组类型):并不是我们工作中所使用的数组String[] 、byte[](这种都属于Class),而是带有泛型的数组,即T[] 泛型数组

Spring提供了更具统一的类型抽象:ResolvableType,但是本文只讲讲解JDK的

Type接口本身算是一个标记接口,不提供任何需要复写的方法

Type的直接子类只有一个,也就是Class,代表着类型中的原始类型以及基本类型。

public interface Type {
    default String getTypeName() {
        return toString();
    }
}

下面就专门针对这些类型做一些案例以及分析~

GenericArrayType(数组类型)

泛型数组,描述的是形如:A< T>[]或T[]类型变量和原始类型

public interface GenericArrayType extends Type {
	//返回泛型数组中元素的Type类型,即List<String>[] 中的 List<String>
	Type getGenericComponentType();
}

Demo:

public class GenericArrayTypeTest<T> {

    // 这里面有各种各样的数组:各有不同 方便看测试效果
    // 含有泛型数组的才是GenericArrayType
    public void testGenericArrayType(List<String>[] pTypeArray, T[] vTypeArray, List<String> list,
                                     List<? extends Number> wildcardList, String[] strings, GenericArrayTypeTest[] test) {
    }


    public static void main(String[] args) {
        Method[] declaredMethods = GenericArrayTypeTest.class.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // main方法不用处理
            if (method.getName().startsWith("main")) {
                continue;
            }

            // 开始处理该方法===打印出此方法签名
            System.out.println("declare Method:" + method); //declare Method:public void com.fsx.maintest.GenericArrayTypeTest.testGenericArrayType(java.util.List[],java.lang.Object[],java.util.List,java.lang.String[],com.fsx.maintest.GenericArrayTypeTest[])

            // 该方法能获取到该方法所有的实际的参数化类型,比如本例中有五个参数,那数组长度就是5
            Type[] types = method.getGenericParameterTypes();

            // 分组打印出来
            for (Type type : types) {

                if (type instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    System.out.println("ParameterizedType type :" + parameterizedType);
                }
                else if (type instanceof GenericArrayType) {
                    // 从结果

                    GenericArrayType genericArrayType = (GenericArrayType) type;
                    System.out.println("GenericArrayType type :" + genericArrayType);

                    Type genericComponentType = genericArrayType.getGenericComponentType();
                    System.out.println("genericComponentType:" + genericComponentType);
                }
                else if (type instanceof WildcardType) {
                    WildcardType wildcardType = (WildcardType) type;
                    System.out.println("WildcardType type :" + wildcardType);
                }
                else if (type instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) type;
                    System.out.println("TypeVariable type :" + typeVariable);
                }
                else {
                    Class clazz = (Class) type;
                    System.out.println("type :" + clazz);
                }
            }
        }
    }

}

输出结果:

declare Method:public void com.fsx.maintest.GenericArrayTypeTest.testGenericArrayType(java.util.List[],java.lang.Object[],java.util.List,java.util.List,java.lang.String[],com.fsx.maintest.GenericArrayTypeTest[])
GenericArrayType type :java.util.List<java.lang.String>[]
genericComponentType:java.util.List<java.lang.String>
GenericArrayType type :T[]
genericComponentType:T
ParameterizedType type :java.util.List<java.lang.String>
ParameterizedType type :java.util.List<? extends java.lang.Number>
type :class [Ljava.lang.String;
type :class [Lcom.fsx.maintest.GenericArrayTypeTest;

在这里插入图片描述
分析:GenericArrayType有两个都是:List<String>[] pTypeArray, T[] vTypeArray它哥俩都是泛型数组。但是这两String[] strings, Main[] test可不是,他俩属于Class普通类型

genericArrayType.getGenericComponentType()返回的类型为ParameterizedTypeImpl类型,能够获取到数组的实际参数类型

ParameterizedType(参数化类型)

参数化类型,即泛型;例如:List< T>、Map< K,V>等带有参数化的对象

public interface ParameterizedType extends Type {
	//获取类型内部的参数化类型 比如Map<K,V>里面的K,V类型
	Type[] getActualTypeArguments();
	// 类的原始类型,一般都是Class
	Type getRawType();
	// 获取所有者类型(只有内部类才有所有者,比如Map.Entry他的所有者就是Map),若不是内部类,此处返回null
    Type getOwnerType();
}

Demo:

public class ParameterizedTypeTest {

    private Map<String, ParameterizedTypeTest> map;
    private Set<String> set1;
    private Class<?> clz;
    private Holder<String> holder;
    private List<String> list;
    private ArrayList<String> arrayList; 
    private Map.Entry<String, String> entry;

    private String str;
    private Integer i;
    private Set set;
    private List aList;

    static class Holder<V> {
    }

    public static void main(String[] args) {
        Field f = null;
        try {
            // 拿到所有的字段
            Field[] fields = ParameterizedTypeTest.class.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                f = fields[i];


                if (f.getGenericType() instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) f.getGenericType();
                    System.out.println(f.getName() + ":");

                    System.out.println("\t ParameterizedType:" + Arrays.asList(parameterizedType.getActualTypeArguments()));
                    System.out.println("\t getRawType:" + parameterizedType.getRawType());
                    System.out.println("\t getOwnerType:" + parameterizedType.getOwnerType());
                }
                // 输出不是ParameterizedType 参数化类型的
                else {
                    System.out.println(f.getName() + ":is not ParameterizedType ");
                }
            }
        } catch (Exception e) {
        }
    }
}

输出:

map:
	 ParameterizedType:[class java.lang.String, class com.fsx.maintest.ParameterizedTypeTest]
	 getRawType:interface java.util.Map
	 getOwnerType:null
set1:
	 ParameterizedType:[class java.lang.String]
	 getRawType:interface java.util.Set
	 getOwnerType:null
clz:
	 ParameterizedType:[?]
	 getRawType:class java.lang.Class
	 getOwnerType:null
holder:
	 ParameterizedType:[class java.lang.String]
	 getRawType:class com.fsx.maintest.ParameterizedTypeTest$Holder
	 getOwnerType:class com.fsx.maintest.ParameterizedTypeTest
list:
	 ParameterizedType:[class java.lang.String]
	 getRawType:interface java.util.List
	 getOwnerType:null
arrayList:
	 ParameterizedType:[class java.lang.String]
	 getRawType:class java.util.ArrayList
	 getOwnerType:null
entry:
	 ParameterizedType:[class java.lang.String, class java.lang.String]
	 getRawType:interface java.util.Map$Entry
	 getOwnerType:interface java.util.Map
str:is not ParameterizedType 
i:is not ParameterizedType 
set:is not ParameterizedType 
aList:is not ParameterizedType 

先看最后几个is not..的。发现即使是List,但是我们没给与泛型,它不会是ParameterizedType参数化类型。
然后holder和entrygetOwnerType不是null,因为他俩类型都是内部类,所以有所有者类型。其它的top类都是null
getRawType其实就是返回了本类的本来的Class类型
getActualTypeArguments:获取到泛型类型,返回一个数组(因为可能会有多个)

WildcardType( 泛型表达式类型)

通配符表达式,或泛型表达式,它虽然是Type的一个子接口,但并不是Java类型中的一种,表示的仅仅是类似 ? extends T、? super K这样的通配符表达式。

?—通配符表达式,表示通配符泛型,但是WildcardType并不属于Java-Type中的一种

public interface WildcardType extends Type {
	//获得泛型表达式上界(上限) 获取泛型变量的上边界(extends) 
	Type[] getUpperBounds();
	//获得泛型表达式下界(下限) 获取泛型变量的下边界(super)
	Type[] getLowerBounds();
}

Demo:

public class WildcardTypeTest {

    private List<? extends Number> listUpper;
    private List<? super String> listLower;
    private List<String> list;

    private Map<? extends String, ? super Number> map1;
    private Map<? extends String, ?> map2;

    private Class<?> clazz;
    // 不写泛型的list
    private List objList;


    private static void printWildcardType(WildcardType wildcardType) {
        for (Type type : wildcardType.getUpperBounds()) {
            System.out.println("\t\t上界:" + type);
        }
        for (Type type : wildcardType.getLowerBounds()) {
            System.out.println("\t\t下界:" + type);
        }
    }

    public static void main(String[] args) {
        Field f = null;
        try {
            Field[] fields = WildcardTypeTest.class.getDeclaredFields();

            for (int i = 0; i < fields.length; i++) {
                f = fields[i];
                System.out.println("begin ******当前field:" + f.getName() + " *************************");
                Type genericType = f.getGenericType(); // 获取字段的泛型参数
                if (genericType instanceof ParameterizedType) {
                    System.out.println("\tParameterizedType type :" + genericType);

                    ParameterizedType parameterizedType = (ParameterizedType) genericType;

                    for (Type type : parameterizedType.getActualTypeArguments()) {
                        //参数化类型可能有多个
                        System.out.println("\t  获取到getActualTypeArguments为:" + type);
                        if (type instanceof WildcardType) {
                            printWildcardType((WildcardType) type);
                        }
                    }
                } else if (genericType instanceof GenericArrayType) {
                    GenericArrayType genericArrayType = (GenericArrayType) genericType;
                    System.out.println("\tGenericArrayType type :" + genericArrayType);
                    Type genericComponentType = genericArrayType.getGenericComponentType();
                    if (genericComponentType instanceof WildcardType) {
                        printWildcardType((WildcardType) genericComponentType);
                    }
                } else if (genericType instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) genericType;
                    System.out.println("\ttypeVariable:" + typeVariable);

                } else {
                    System.out.println("\ttype :" + genericType);
                    if (genericType instanceof WildcardType) {
                        printWildcardType((WildcardType) genericType);
                    }
                }
                System.out.println("end ******当前field:" + f.getName() + " *************************");
                System.out.println();
            }
        } catch (Exception e) {
        }
    }
}

输出:

开始 ******当前field:listUpper *************************
	ParameterizedType type :java.util.List<? extends java.lang.Number>
	  获取到getActualTypeArguments为:? extends java.lang.Number
		上界:class java.lang.Number
结束 ******当前field:listUpper *************************

开始 ******当前field:listLower *************************
	ParameterizedType type :java.util.List<? super java.lang.String>
	  获取到getActualTypeArguments为:? super java.lang.String
		上界:class java.lang.Object
		下界:class java.lang.String
结束 ******当前field:listLower *************************

开始 ******当前field:list *************************
	ParameterizedType type :java.util.List<java.lang.String>
	  获取到getActualTypeArguments为:class java.lang.String
结束 ******当前field:list *************************

开始 ******当前field:map1 *************************
	ParameterizedType type :java.util.Map<? extends java.lang.String, ? super java.lang.Number>
	  获取到getActualTypeArguments为:? extends java.lang.String
		上界:class java.lang.String
	  获取到getActualTypeArguments为:? super java.lang.Number
		上界:class java.lang.Object
		下界:class java.lang.Number
结束 ******当前field:map1 *************************

开始 ******当前field:map2 *************************
	ParameterizedType type :java.util.Map<? extends java.lang.String, ?>
	  获取到getActualTypeArguments为:? extends java.lang.String
		上界:class java.lang.String
	  获取到getActualTypeArguments为:?
		上界:class java.lang.Object
结束 ******当前field:map2 *************************

开始 ******当前field:clazz *************************
	ParameterizedType type :java.lang.Class<?>
	  获取到getActualTypeArguments为:?
		上界:class java.lang.Object
结束 ******当前field:clazz *************************

开始 ******当前field:objList *************************
	type :interface java.util.List
结束 ******当前field:objList *************************

我们能够发现,字段的f.getGenericType()绝大部分都是返回的ParameterizedType类型,从而可以继续使用getActualTypeArguments拿到具体类型。看看是不是WildcardType类型

像这种private List objList,它f.getGenericType()直接就是interface java.util.List

Map它可以有多个泛型表达式类型。另外需要说明的一点是:表达式中,如果你没有指定上线,默认都是有上限的:class java.lang.Object,但是下限不会有默认值

泛型中使用 & (并且)操作符

我们不乏有时候能够看到泛型搭配上 & 的使用方式,比如:

static <R extends Enum<R> & BaseIntEnum> List<R> parse2Enums(...){...}

首先说明一点:&不能用于?通配符上(因为通配符不能放在泛型的申明上)
&只能放在泛型的声明上。比如类似这种:

public class WildcardTypeTest<T extends Comparable<T> & List<T> & Serializable> { ... }
// 或者方法上申明泛型也成
static <R extends Enum<R> & BaseIntEnum> List<R> parse2Enums(...){...}

需要注意的是,& 后面只能放置接口,而不能是具体类型。连Object都不行

因此当我们需要泛型的多重约束的时候,可以使用此并且&操作符。但是它不能用于super上,因为Java有规定:

class A<T extends Number> is allowed

but

class A<T super Integer> is not allowed

原因请参考:Why super keyword in generics is not allowed at class level
下文也有详细分解

TypeVariable(类型变量)

泛型的类型变量,指的是List< T>、Map< K,V>中的T,K,V等值,实际的Java类型是TypeVariableImpl(TypeVariable的子类;此外,还可以对类型变量加上extend限定,这样会有类型变量对应的上限;值得注意的是,类型变量的上限可以为多个,必须使用&符号相连接,例如 List< T extends Number & Serializable>;其中,& 后必须为接口;

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
	//类型对应的上限,默认为Object  可以有多个
    Type[] getBounds();
    //获取声明该类型变量实体,也就是TypeVariableTest< T>中的TypeVariableTest
    D getGenericDeclaration();
    //获取类型变量在源码中定义的名称;
    String getName();
    // JDK8新增的
    AnnotatedType[] getAnnotatedBounds();
}

Demo:

public class TypeVariableTest<T extends Number & Serializable, V> {

    private T key;
    private V value;
    // 显然它本身是个GenericArrayType类型,里面是TypeVariable类型
    private V[] values;
    //ParameterizedType 和 TypeVariable的结合
    private List<T> tList;

    private String str;


    private static void printTypeVariable(String fieldName, TypeVariable typeVariable) {
        for (Type type : typeVariable.getBounds()) {
            System.out.println("\t\t" + fieldName + ": TypeVariable getBounds " + type);
        }
        System.out.println("\t\t定义Class getGenericDeclaration: " + typeVariable.getGenericDeclaration());
        System.out.println("\t\tgetName: " + typeVariable.getName());
    }

    public static void main(String[] args) {
        Field f = null;
        try {
            Field[] fields = TypeVariableTest.class.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                f = fields[i];
                if (f.getName().equals("log")) {
                    continue;
                }
                System.out.println("开始 ******当前field:" + f.getName() + " *************************");
                Type genericType = f.getGenericType();

                if (genericType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) genericType;
                    for (Type type : parameterizedType.getActualTypeArguments()) {
                        System.out.println("\t获取ParameterizedType:" + type);
                        if (type instanceof TypeVariable) {
                            printTypeVariable(f.getName(), (TypeVariable) type);
                        }
                    }
                    System.out.println("\tgetOwnerType:" + parameterizedType.getOwnerType());
                    System.out.println("\tgetRawType:" + parameterizedType.getRawType());

                } else if (genericType instanceof GenericArrayType) {
                    GenericArrayType genericArrayType = (GenericArrayType) genericType;
                    System.out.println("GenericArrayType type :" + genericArrayType);
                    Type genericComponentType = genericArrayType.getGenericComponentType();
                    if (genericComponentType instanceof TypeVariable) {
                        TypeVariable typeVariable = (TypeVariable) genericComponentType;
                        printTypeVariable(f.getName(), typeVariable);
                    }
                } else if (genericType instanceof TypeVariable) {
                    TypeVariable typeVariable = (TypeVariable) genericType;
                    printTypeVariable(f.getName(), typeVariable);
                } else {
                    System.out.println("type :" + genericType);
                }
                System.out.println("结束 ******当前field:" + f.getName() + " *************************");
                System.out.println();
            }
        } catch (Exception e) {
        }
    }

}

输出:

开始 ******当前field:key *************************
		key: TypeVariable getBounds class java.lang.Number
		key: TypeVariable getBounds interface java.io.Serializable
		定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest
		getName: T
结束 ******当前field:key *************************

开始 ******当前field:value *************************
		value: TypeVariable getBounds class java.lang.Object
		定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest
		getName: V
结束 ******当前field:value *************************

开始 ******当前field:values *************************
GenericArrayType type :V[]
		values: TypeVariable getBounds class java.lang.Object
		定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest
		getName: V
结束 ******当前field:values *************************

开始 ******当前field:tList *************************
	获取ParameterizedType:T
		tList: TypeVariable getBounds class java.lang.Number
		tList: TypeVariable getBounds interface java.io.Serializable
		定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest
		getName: T
	getOwnerType:null
	getRawType:interface java.util.List
结束 ******当前field:tList *************************

开始 ******当前field:str *************************
type :class java.lang.String
结束 ******当前field:str *************************

可以看出:TypeVariable是可以有多个的。可以使用getBounds拿出来,它返回的是数组(表名是支持多个的嘛)
V虽然啥都没写,但是也是有上限:java.lang.Object
普通类型比如String,它啥都木有~~~~属于Class类型

Class(原始/基本类型)

**Type的直接子类只有一个,也就是Class,代表着类型中的原始类型以及基本类型。**Class —— 反射基石

其意义为:类的抽象,即对“类”做描述:比如类有修饰、字段、方法等属性,有获得该类的所有方法、所有公有方法等方法。同时,Class也是Java类型中最重要的一种,表示原始类型(引用类型)及基本类型。

与泛型有关的类型不能和原始类型统一到Class的原因

产生泛型擦除的原因

原始类型和新产生的类型都应该统一成各自的字节码文件类型对象。但是由于泛型不是最初Java中的成分。如果真的加入了泛型,涉及到JVM指令集的修改,这是非常致命的(简单的说就是Java要向下兼容,所以它的泛型是个假东西

Java 引入泛型擦除的原因是避免因为引入泛型而导致运行时创建不必要的类。那我们其实就可以通过定义类的方式,在类信息中保留泛型信息,从而在运行时获得这些泛型信息。
简而言之,Java 的泛型擦除是有范围的,即类定义中的泛型是不会被擦除的

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        Type type = map.getClass().getGenericSuperclass(); // 获取HashMap父类AbstractMap<K,V>  请注意:此处为<K,V>
        ParameterizedType parameterizedType = ParameterizedType.class.cast(type);

        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); // 两个类型  一个是K,一个是V
        for (Type typeArgument : actualTypeArguments) {
            System.out.println(typeArgument.getTypeName()); //k,v(泛型消失了)
        }
    }


// 泛型不消失的情况对比
public class Main {

    private static class HashMapEx<K, V> extends HashMap<K, V> {
        public HashMapEx() {
            super();
        }
    }

    public static void main(String[] args) {
        // 此处必须用匿名内部类的方式写,如果使用new HashMapEx<String,Integer> 效果同上
        Map<String, Integer> map = new HashMap<String, Integer>() {
        };

        Type type = map.getClass().getGenericSuperclass(); // 获取HashMapEx父类HashMap<K,V>
        ParameterizedType parameterizedType = ParameterizedType.class.cast(type);

        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); // 两个类型  一个是K,一个是V
        for (Type typeArgument : actualTypeArguments) {
            System.out.println(typeArgument.getTypeName()); //k,v(泛型消失了)
        }
    }
}

getSuperclass 返回直接继承的父类(由于编译擦除,没有显示泛型参数)
getGenericSuperclass:返回直接继承的父类(包含泛型参数) 1.5后提供

    public static void main(String[] args) {
        // 此处必须用匿名内部类的方式写,如果使用new HashMapEx<String,Integer> 效果同上
        Map<String, Integer> map = new HashMap<String, Integer>() {
        };
        System.out.println(map.getClass().getSuperclass()); //class java.util.HashMap
        System.out.println(map.getClass().getGenericSuperclass()); //java.util.HashMap<java.lang.String, java.lang.Integer>

        // 但是如果是不带泛型的,两者等价
        Integer i = new Integer(1);
        System.out.println(i.getClass().getSuperclass()); //class java.lang.Number
        System.out.println(i.getClass().getGenericSuperclass()); //class java.lang.Number
    }
Java中如何引入泛型

为了使用泛型又不真正引入泛型,Java采用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是,一旦编译完成,所有的和泛型有关的类型全部擦除。

Class不能表达与泛型有关的类型

因此,与泛型有关的参数化类型、类型变量类型、限定符类型 、泛型数组类型这些类型编译后全部被打回原形,在字节码文件中全部都是泛型被擦除后的原始类型并不存在和自身类型对应的字节码文件。所以和泛型相关的新扩充进来的类型不能被统一到Class类中。

与泛型有关的类型在Java中的表示

为了通过反射操作这些类型以迎合实际开发的需要,Java就新增了ParameterizedType, TypeVariable<D>, GenericArrayType, WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。

引入Type的原因

为了程序的扩展性,最终引入了Type接口作为Class和ParameterizedType, TypeVariable, GenericArrayType, WildcardType这几种类型的总的父接口。这样可以用Type类型的参数来接受以上五种子类的实参或者返回值类型就是Type类型的参数。统一了与泛型有关的类型和原始类型Class

Type接口中没有方法的原因

从上面看到,Type的出现仅仅起到了通过多态来达到程序扩展性提高的作用,没有其他的作用。因此Type接口的源码中没有任何方法。

最后用一个我们最常用的例子:反射获取泛型类型。给出解决方案如下

反射获取类的泛型类型

这个还是非常有用的,比如我们在常用的泛型基类设计中可以这么写

public class BaseDaoImpl<T> implements BaseDao<T> {

	// 它代表着实际类型
    private Class<T> beanClass;
    
    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        ParameterizedType parameterizedType=(ParameterizedType)this.getClass().getGenericSuperclass();
        beanClass=(Class<T>) parameterizedType.getActualTypeArguments()[0];
    }
    // 省略具体的操作....
}

说明:Class类有两个"雷同"的方法:

    public native Class<? super T> getSuperclass(); //返回直接继承的父类(不显示泛型参数)
    // @since 1.5
    public Type getGenericSuperclass(); // 返回直接继承的父类 显示泛型参数

从返回值或许就能看出差异。他俩从执行结果上,更能看出差异:

Student.class.getSuperclass()	class cn.test.Person
Student.class.getGenericSuperclass()	cn.test.Person<cn.test.Test>
总结

我们知道,Type是JDK5开始引入的,其引入主要是为了泛型,没有泛型的之前,只有所谓的原始类型。此时,所有的原始类型都通过字节码文件类Class类进行抽象。Class类的一个具体对象就代表一个指定的原始类型。

泛型出现之后,也就扩充了数据类型。从只有原始类型扩充了参数化类型、类型变量类型、泛型数组类型,也就是Type的子接口
  那为什么没有统一到Class下,而是增加一个Type呢?(Class也是种类的意思,Type是类型的意思)
  
  是为了程序的扩展性,最终引入了Type接口作为Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType这几种类型的总的父接口。
  这样实现了Type类型参数接受以上
五种子类的实参
或者返回值类型就是Type类型的参数。

List<T ? entends>[]:这里的List就是ParameterizedType,T就是TypeVariable,T ? entends就是WildcardType(注意,WildcardType不是Java类型,而是一个表达式),整个List<T ? entends>[]就是GenericArrayType


关注A哥

AuthorA哥(YourBatman)
个人站点www.yourbatman.cn
E-mailyourbatman@qq.com
微 信fsx641385712
活跃平台
公众号BAT的乌托邦(ID:BAT-utopia)
知识星球BAT的乌托邦
每日文章推荐每日文章推荐

BAT的乌托邦

  • 10
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 这个错误是因为在Java中,一个类不能被强制转换为ParameterizedType类型。通常是因为在使用反射时,尝试将一个Class对象转换为ParameterizedType对象,但是这个Class对象实际上不是一个ParameterizedType类型。要解决这个问题,需要检查代码中的反射使用,确保正确地使用了ParameterizedType类型。 ### 回答2: java.lang.Class无法强制转换为java.lang.reflect.ParameterizedType。 在Java中,java.lang.Class类表示运行时类的信息和属性,而java.lang.reflect.ParameterizedType接口表示带有参数的类型(泛型类型)。 这个错误是因为在尝试将Class对象强制转换为ParameterizedType对象时,类型转换发生了错误。 要解决这个问题,我们需要理解java.lang.reflect.ParameterizedType的使用情况。 ParameterizedType接口是Type接口的子接口,可以用于获取带有参数的类型信息,例如泛型类或泛型接口的类型参数信息。 如果我们想要获得一个类的泛型参数类型信息,我们可以使用java.lang.Class类中的getGenericSuperclass()方法或getGenericInterfaces()方法。 但是要注意,这些方法返回的类型是java.lang.reflect.Type,而不是java.lang.reflect.ParameterizedType。 如果我们想要将Type对象转换为ParameterizedType对象,我们需要进行类型检查和类型转换。 示例代码: import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; public class MyClass<T> { public MyClass() { Type type = getClass().getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; // 在这里可以使用ParameterizedType对象来获取泛型参数类型信息 } } } 总结来说,java.lang.Class不能直接强制转换为java.lang.reflect.ParameterizedType,我们需要根据具体的使用情况进行类型检查和转换才能正确地获取泛型参数类型信息。 ### 回答3: java.lang.Class不能被转换为java.lang.reflect.ParameterizedType的原因是两者表示的是不同的类型信息。java.lang.Class用于表示类的信息,而java.lang.reflect.ParameterizedType用于表示泛型类型的信息。 当使用强制类型转换将一个对象转换为java.lang.reflect.ParameterizedType时,如果该对象实际上是java.lang.Class类型的对象,就会抛出ClassCastException。这是因为java.lang.Class和java.lang.reflect.ParameterizedType是不兼容的类型。 如果需要获取一个类中的泛型类型信息,应该使用java.lang.Class对象的getGenericSuperclass()方法来获取其父类的泛型类型信息,再通过强制类型转换获取到java.lang.reflect.ParameterizedType对象。 例如: ``` class MyGenericClass<T> { } class MyClass extends MyGenericClass<String> { } public static void main(String[] args) { MyClass myClass = new MyClass(); ParameterizedType parameterizedType = (ParameterizedType) myClass.getClass().getGenericSuperclass(); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); Type actualTypeArgument = actualTypeArguments[0]; String genericType = actualTypeArgument.getTypeName(); System.out.println(genericType); } ``` 如果在强制类型转换时抛出了java.lang.ClassCastException,可以检查代码中的类型转换部分,并确保正确使用泛型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值