2.2 泛型接口
泛型接口和泛型类相似,在类名后加上一对尖括号 <T,T...>来定义:
public interface Generator<T> {
public T next();
}
实现泛型接口时,实现类可以为泛型类型,实现类的参数类型会传递到泛型接口中:
public class TeaGenerator<T> implements Generator<T> {
@Override
public T next() {
return null;
}
}
也可以为泛型接口指定固定的类型:
public class StringGenerator implements Generator<String> {
@Override
public String next() {
return null;
}
}
指定了固定类型String以后,泛型接口里的相应方法,实现时也要改成String。
2.3 泛型方法
泛型方法和泛型类相似,可以将类型像参数一样传递,把一个泛型参数列表<T,T...>定义在方法的返回值之前,泛型方法中的类型参数,只在声明它的作用域内有效。
public static <T> void test(T para)
泛型方法有时在泛型类中使用,初学者容易把泛型方法,和泛型类中的成员方法搞混,我们区分一下以下几种情况:
public class Box<T> {
private T id;
//泛型中的成员方法 。
// T 来自于泛型类,是返回值。泛型中的成员方法 。 T 来自于泛型类,是返回值。
private T openBox() {
return id;
}
/**
* 泛型方法。 在返回值前用<E>声明,后面的E是返回值。
*/
private <E> E openBox(E id) {
return id;
}
//泛型方法。注意 这里的<T>和泛型类没有关系,
// 是属于泛型方法自己的。 在返回值前用<T>声明,后面的T是返回值。
private <T> T closeBox(T id) {
return id;
}
}
3.泛型的一些特性
3.1 多种类型参数
在使用泛型类,泛型接口,或泛型方法时,用 <T,...>
包裹的类型参数列表,里面可以定义多个类型参数。
public class Pair<K, V> {
private K key;
private V value;
Pair(K key, V value) {
this.key = key;
this.value = value;
}
}
3.2 有界类型参数
有时候使用泛型,我们希望可以限制它的上下边界,比如我希望一个泛型方法只处理Number类型的数据,这个时候我们可以在参数列表里使用extends
关键字来限制类型参数的"上界",可以看做是继承/实现关系:
public static <T extends Number, E extends Number> int divide(T n1, E n2) {
return n1.intValue() / n2.intValue();
}
这样就可以让我们传入的参数类型,使用Number类中定义的方法,此时类型参数T可以看做是Number的子类来使用。
类型参数的"下界"使用super
关键字来定义,可以看做参数类型是指定类型的父类:
public static <T super Integer, E extends Number> int divide(T n1, E n2) {
return n1.intValue() / n2.intValue();
}