8. 尚硅谷_Java基础_泛型
泛 型
1. 介绍
下面是那种典型用法:
List myIntList = new ArrayList();// 1
myIntList.add(new Integer(0));// 2
Integer x = (Integer) myIntList.iterator().next();// 3
第 3 行的类型转换有些烦人。通常情况下,程序员知道一个特定的 list
里边放的是什么类型的数据。但是,这个类型转换...
泛 型
1. 介绍
下面是那种典型用法:
List myIntList = new ArrayList();// 1
myIntList.add(new Integer(0));// 2
Integer x = (Integer) myIntList.iterator().next();// 3
第 3 行的类型转换有些烦人。通常情况下,程序员知道一个特定的 list
里边放的是什么类型的数据。但是,这个类型转换是必须的(essential)。编
译器只能保证 iterator 返回的是 Object 类型。为了保证对 Integer 类型变量
赋值的类型安全,必须进行类型转换。
当然,这个类型转换不仅仅带来了混乱,它还可能产生一个运行时错误
(run time error),因为程序员可能会犯错。
程序员如何才能明确表示他们的意图,把一个 list(集合) 中的内容限制
为一个特定的数据类型呢?这就是 generics 背后的核心思想。这是上面程
序片断的一个泛型版本:
List myIntList = new ArrayList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = myIntList.iterator().next(); // 3
注意变量 myIntList 的类型声明。它指定这不是一个任意的 List,而是
一个 Integer 的 List,写作:List。我们说 List 是一个带一个类型
参数的泛型接口(a generic interface that takes a type parameter),本
例中,类型参数是 Integer。我们在创建这个 List 对象的时候也指定了一个
类型参数。
另一个需要注意的是第 3 行没了类型转换。
现在,你可能认为我们已经成功地去掉了程序里的混乱。我们用第 1
行的类型参数取代了第 3 行的类型转换。然而,这里还有个很大的不同。
编译器现在能够在编译时检查程序的正确性。当我们说 myIntList 被声明为
List类型,这告诉我们无论何时何地使用 myIntList 变量,编译器
保证其中的元素的正确的类型。
实际结果是,这可以增加可读性和稳定性(robustness),尤其在大型的
程序中。
2. 定义简单的泛型
下面是从 java.util 包中的 List 接口和 Iterator 接口的定义中摘录的片断:
public interface List {
void add(E x);
Iterator iterator();
}
public interface Iterator {
E next();
boolean hasNext();
}
这些都应该是很熟悉的,除了尖括号中的部分,那是接口 List 和 Iterat
or 中的形式类型参数的声明(the declarations of the formal type param
eters of the interfaces List and Iterator)。
类型参数在整个类的声明中可用,几乎是所有可以使用其他普通类型的
地方
在介绍那一节我们看到了对泛型类型声明 List (the generic type decl
aration List) 的调用,如 List。在这个调用中(通常称作一个参数
化类型 a parameterized type),所有出现的形式类型参数(formal type pa
rameter,这里是 E)都被替换成实体类型参数(actual type argument)(这里
是 Integer)。
你可能想象,List代表一个 E 被全部替换成 Integer 的版本:
public interface IntegerList {
void add(Integer x)
Iterator iterator();
}
类型参数就跟在方法或构造函数中普通的参数一样。就像一个方法有形
式参数(formal value parameters)来描述它操作的参数的种类一样,一个
泛型声明也有形式类型参数(formal type parameters)。当一个方法被调用,
实参(actual arguments)替换形参,方法体被执行。当一个泛型声明被调用,
实际类型参数(actual type arguments)取代形式类型参数。
一个命名的习惯:推荐用简练的名字作为形式类型参数的名字(如果可
能,单个字符)。最好避免小写字母
3. 泛型和子类继承
让我们测试一下我们对泛型的理解。下面的代码片断合法么?
List ls = new ArrayList(); //1
List