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