泛型类中的类型参数几乎可以用于任何可以使用接口名、类名的地方,下面我们先通过 JDK 5.0 中集合框架中的 Map 接口定义的一部分来简单了解一下:

public interface Map<K, V> {
    public void put(K key, V value);
    public V get(K key);
    //......
}

对于常见的泛型模式,推荐的名称是:

K ——键,比如映射的键。

V ——值,比如 List 和 Set 的内容,或者 Map 中的值。

E ——异常类。

T ——泛型。

其中,T、E、K、V不代表值,而是表示类型。它们不能用基本数据类型填充,也就是说泛型的类型参数只能是类类型(包括自定义类),不能是简单类型(基本数据类型)。

当声明或者实例化一个泛型的对象时,必须指定类型参数的值:

Map<String, String> map = new HashMap<String, String>();

 

泛型类

泛型类型用于类的定义中,被称为泛型类。

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。

泛型类的类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。

一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

通过泛型可以完成对一组类的操作对外开放相同的接口。

泛型类的声明:

class 类名称 <泛型标识> {
    private 泛型标识 变量名; 
    //....
}

自定义泛型类的示例:

/**
 * 此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型;
 * <T>是在声明泛型类声明过的泛型, 泛型类里的方法才可以继续使用 T 这个泛型
 */
public class GenericClassDemo<T> { 
    //key这个成员变量的类型为T,T的类型由外部指定  
    private T t;
    // 无参构造
    public GenericClassDemo() { 
    }
    //泛型构造方法形参t的类型也为T,T的类型由外部指定
    public GenericClassDemo(T t) { 
        this.t = t;
    }
    /**
     * 泛型方法setT形参t的类型也为T, T的类型由外部指定
     * 虽然在方法中使用了泛型,但是这并不是一个泛型方法。
     */
    public void setT(T t) {
        this.t = t;
    }
     /**
     * 泛型方法getT的返回值类型为T,T的类型由外部指定
     * 虽然在方法中使用了泛型,但是这并不是一个泛型方法。
     */
    public T getT(){ 
        return t;
    }
}

下面我们来创建测试一下:

// 传入的实参类型需与泛型的类型参数类型相同,
// 且泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
GenericClassDemo<String> genericStr = new GenericClassDemo<String>("demo");
GenericClassDemo<Integer> genericInt = new GenericClassDemo<Integer>();
genericInt.setT(120);
System.out.println("String: " + genericStr.getT());  // String: demo
System.out.println("Integer: " + genericInt.getT());  // Integer: 120

定义的泛型类,就一定要传入泛型类型实参么?并不是这样,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

GenericClassDemo genericStr = new GenericClassDemo("demo");
GenericClassDemo genericChr = new GenericClassDemo('a');
GenericClassDemo genericInt = new GenericClassDemo();
genericInt.setT(new Integer(120));
System.out.println("String: " + genericStr.getT());  // String: demo
System.out.println("Charactor: " + genericChr.getT());  // Charactor: a
System.out.println("Integer: " + genericInt.getT());  // Integer: 120

 

泛型接口

泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中。

public interface GeneratorInterfaceDemo<T> {
    public T get();
}

当实现泛型接口的类,未传入泛型实参时:

/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * 即:class GenericImp<T> implements GenericInterfaceDemo<T>{
 * 如不声明泛型, 如:class GenericImp implements GenericInterfaceDemo<T>,
 * 编译器会报错"Unknown class"
 */
class GenericImp<T> implements GenericInterfaceDemo<T>{
    @Override
    public T get() {
        return null;
    }
}

当实现泛型接口的类,传入泛型实参时:

/**
 * 虽然我们只创建了一个泛型接口GenericInterfaceDemo<T>
 * 但是我们可以为T传入无数个实参,形成无数种类型的GenericInterfaceDemo接口。
 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型(如下传入String),
 * 则所有使用泛型的地方都要替换成传入的实参类型,
 * 即:GenericInterfaceDemo<T>,public T get();中的的T都要替换成传入的String类型。
 */
public class GenericStrImp implements GenericInterfaceDemo<String> {
    private String[] strs = new String[]{"Apple", "Banana", "Pear"};
    @Override
    public String get() {
        Random rand = new Random();
        return strs[rand.nextInt(3)];
    }
}