今天主要说说泛型中的继承规则以及通配符相关的内容。
泛型中的继承规则
我们定义这样一个泛型类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package com;
public class Result<T>
{
private T value;
public T getValue()
{
return value;
}
public void setValue(T value)
{
this.value = value;
}
}
那么Result<Person>
和Result<Student>
有什么关系呢,其中Student是Person类的子类。
答案是他们没有关系,Result<Student>
并不是Result<Person>
的子类,通常无论S和T有什么关系,Result<S>
和Result<T>
都没有什么关系。
泛型类可以扩展或实现其他泛型类或泛型接口,这跟普通的类和接口没有区别。
通配符类型
通配符的子类型限定
通过泛型类型的继承规则,我们知道,Result<Student>
和Result<Person>
并没有什么关系,换言之他们是不同的类型,下面我们想定义一个printName方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32//首先定义Student类和Person类
package com;
public class Person
{
private String name;
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
package com;
public class Student extends Person
{
public Student(String name)
{
super(name);
}
}
定义printName函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package com;
public class Main
{
public static void main(String[] args)
{
Person xiaoming = new Person("xiaoming");
Student xiaoqiang = new Student("xiaoqiang");
Result<Person> input1 = new Result<>();
input1.setValue(xiaoming);
Result<Student> input2 = new Result<>();
input2.setValue(xiaoqiang);
printName(input1);
printName(input2);//报编译错误
}
public static void printName(Result<Person> input)
{
System.out.println(input.getValue().getName());
}
}
我们发现printName(input2);
语句报编译错误,如果我们想打印Result<Student>
类型入参的姓名,得再定义一个printName方法,参数类型为Result<Student>
。
这样就显得很冗余,那么可以考虑使用通配符来解决:1
2
3
4public static void printName(Result<? extends Person> input)
{
System.out.println(input.getValue().getName());
}
? extends Person
表示Person的所有子类。
通配符的超类型限定
通配符除了可以指定子类型限定,还可以指定超类型限定,语法如下:1
? super Student
表示Student类的所有超类型。
泛型类型的约束与局限
最后总结一下泛型的约束与局限性,大多数约束都是由于类型擦除导致的。
- 不能使用基本类型实例化类型参数。
因此没有Result<double>
,只有Result<Double>
,这是因为类型擦除导致的,擦除之后Result类的成员为Object类型,而Object不能存储double这样的基本类型。- 运行时类型查询只适用原始类型。
因为虚拟机中的对象总有一个特定的非泛型类型,所以所有的类型查询只产生原始类型。
比如if(a instanceof Pair<String>
,实际上等价于if(a instanceof Pair<T>
。- 不能抛出也不能捕获泛型类异常。
事实上,泛型类扩展Throwable都不合法:public class Problem<T> extends Exception{...}
不能通过编译。- 参数化类型的数组不合法
Pair<String>[] table = new pair<String>[10]
是错误的。- 不能实例化类型变量。
不能使用像new T();T.class
之类的表达式。- 泛型类的静态上下文中类型变量无效
1
2
3
4
5 public class Singleton<T>
{
public static T getSingleInstance()//Error
{...}
}