泛型中的继承规则
我们定义这样一个泛型类:
1 | package com; |
那么Result<Person>
和Result<Student>
有什么关系呢,其中Student
是Person
类的子类。
答案是他们没有关系,Result<Student>
并不是Result<Person>
的子类,通常无论S和T有什么关系,Result<S>
和Result<T>
都没有什么关系。
泛型类可以扩展或实现其他泛型类或泛型接口,这跟普通的类和接口没有区别。
通配符类型
通配符的子类型限定
通过泛型类型的继承规则,我们知道,Result<Student>
和Result<Person>
并没有什么关系,换言之他们是不同的类型,下面我们想定义一个printName方法:
1 | //首先定义Student类和Person类 |
定义printName函数:
1 | package com; |
我们发现printName(input2);语句报编译错误,如果我们想打印Result
这样就显得很冗余,那么可以考虑使用通配符来解决:
1 | public static void printName(Result<? extends Person> input) |
? extends Person
表示Person
的所有子类。
通配符的超类型限定
通配符除了可以指定子类型限定,还可以指定超类型限定,语法如下:
1 | ? super Student |
表示Student类的所有超类型。
泛型类型的约束与局限
最后总结一下泛型的约束与局限性,大多数约束都是由于类型擦除导致的。
- 不能使用基本类型实例化类型参数。
因此没有Result,只有Result ,这是因为类型擦除导致的,擦除之后Result类的成员为Object类型,而Object不能存储double这样的基本类型。
- 运行时类型查询只适用原始类型。
因为虚拟机中的对象总有一个特定的非泛型类型,所以所有的类型查询只产生原始类型。
比如if(a instanceof Pair,实际上等价于if(a instanceof Pair 。
- 不能抛出也不能捕获泛型类异常。
事实上,泛型类扩展Throwable都不合法:public class Problemextends Exception{…}不能通过编译。
- 参数化类型的数组不合法
Pair[] table = new pair [10]是错误的。
- 不能实例化类型变量。
不能使用像new T();T.class之类的表达式。
- 泛型类的静态上下文中类型变量无效
1 | public class Singleton<T> |