基础定义
泛型,即“参数化类型”。定义方法时有形参,调用方法时传递实参,参数化类型就是将类型由原来的具体类型参数化,类似与方法中的变量参数,此时类型也定义成参数形式(可以称位类型参数),然后在使用/调用时传入具体的参数(类型实参)。
|
|
采用泛型写法后,在//1处想加入一个Integer类型的对象时会出现编译错误,通过List
结合上面的泛型定义,我们知道在List
我们可以看到,在List接口中采用泛型化定义之后,
自然的,ArrayList作为List接口的实现类,其定义形式是:
自定义泛型接口和泛型类
泛型类中的类型参数几乎可以用于任何可以使用接口名、类名的地方,下面的代码示例展示了 JDK 5.0 中集合框架中的 Map 接口的定义的一部分:
当声明或者实例化一个泛型的对象时,必须指定类型参数的值:
Map
对于常见的泛型模式,推荐的名称是:
K ——键,比如映射的键。
V ——值,比如 List 和 Set 的内容,或者 Map 中的值。
E ——异常类。
T ——泛型。
|
|
自定义泛型方法
泛型方法:泛型方法使得该方法能独立于类而产生变化。以下是一个基本的指导原则:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更清楚明白。另外,对于一个static的方法而言,无法访问泛型类的类型参数。所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。
要定义泛型方法,只需将泛型参数列表置于返回值之前,就像下面这样:
可变参数与泛型方法
泛型方法与可变参数列表能很好地共存:
静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
泛型统配符
|
|
类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参!且Box<?>在逻辑上是Box
类型通配符上限通过形如Box<? extends Number>形式定义,相对应的,类型通配符下限为Box<? super Number>形式,其含义与类型通配符上限正好相反。
泛型的应用
注意事项
- Java中没有所谓的泛型数组一说
- 泛型到底代表什么类型取决于调用者传入的类型,如果没传,默认是Object类型;
- 使用带泛型的类创建对象时,等式两边指定的泛型必须一致;
原因:编译器检查对象调用方法时只看变量,然而程序运行期间调用方法时就要考虑对象具体类型了; 等式两边可以在任意一边使用泛型,在另一边不使用(考虑向后兼容);
ArrayListal = new ArrayList ArrayList<?extends Object> al = new ArrayList
();
al.add(“aa”); //错
//因为集合具体对象中既可存储String,也可以存储Object的其他子类,所以添加具体的类型对象不合适,类型检查会出现安全问题。 ? extendsObject 代表Object的子类型不确定,怎么能添加具体类型的对象呢?public static voidmethod(ArrayList<? extends Object> al) {
al.add(“abc”); //错
//只能对al集合中的元素调用Object类中的方法,具体子类型的方法都不能用,因为子类型不确定。- 所有的标准集合接口都是泛型化的—— Collection
、List 、Set 和 Map 。类似地,集合接口的实现都是用相同类型参数泛型化的,所以HashMap 实现 Map 等。 - Java泛型中的标记符含义:
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
S、U、V - 2nd、3rd、4th types