泛型引言
一般的类和方法,只能使用具体的类型,要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板代码就会对代码的束缚就会很大。
因此,为了编写更为通用的方法,使代码能够运用于"某种不确定"的类型,而不是一个具体的接口或者类。
于是在Java SE5中引入了泛型的概念。泛型实现了参数化类型的概念吗,使得代码可以运用于多种类型。
尽管Java的泛型系统也有其不完美的地方,例如其擦除机制。但是在大多数情况下,泛型可以使代码更为优雅。
简单泛型
public class Holder1 {
private Automobile automobile;
public Holder1(Automobile automobile) {this.automobile = automobile;}
public Automobile getAutomobile() {return automobile;}
}
class Automobile{}
Holder1
可以持有单个私有对象并获取其引用,不过这个类可无法持有其他类型的对象,其可重用性较低。假如其要实现持有别的类型,则只能为碰到的每一个类编写一个新的类。
在Java SE5以前,我们可以让这个类直接持有Object类型的对象。
public class Holder2 {
private Object a;
public Holder2(Object a) {this.a = a;}
public Object get() {return a;}
public void set(Object a) {this.a = a;}
public static void main(String[] args) {
Holder2 h2 = new Holder2(new Automobile())
Automobile a = (Automobile) h2.get();
h2.set("Not an Automobile");
String s = (String) h2.get();
h2.set(1);
Integer x = (Integer) h2.get();
}
}
现在,Holder
可以通过a
字段来储存任何类型的对象,并在main
方法中,只用了一个Holder
对象,却可以存储三种不同类型的对象。
在有些情况下,我们确实希望容器能够同时持有多种类型的对象。但是通常而言,我们只会使用容器来存储一种类型的对象。而泛型的主要目的之一就是用来指定容器要持有什么类型的对象,并且由编译器来确保类型的正确性。
因此,比起直接使用Object
类型的字段,我们更倾向于暂时不指定其类型,而是在使用的过程中再决定其具体使用什么类型,要达到这个目的,需要使用Java SE5中引入的泛型。我们需要提供类型参数,并且用尖括号扩住,放在类名后面。然后在使用这个类的时候,再用实际的类型替换此类型的参数。
public class Holder3<T> {
private T a;
public Holder3(T a) {this.a = a;}
public T get() {return a;}
public void set(T a) {this.a = a;}
public static void main(String[] args) {
Holder3<Automobile> h3 = new Holder3<>(new Automobile());
Automobile a = h3.get();// No cast neededd
// h3.set("Not an Automobile"); //compile err
// h3.set(1); //compile err
}
}
在上面的例子中,T
就是类型参数。
当要创建Holder3
对象的时候,必须指明要在持有什么类型的对象,并将类名止于尖括号内,就像main
中的一样。然后,你就只能在Holder3
里面存入该类型(或者其子类,因为多态和泛型并不冲突)的对象。并且,从Holder3
中取出它所持有的对象的时候,自然就是珍贵的类型。
这就是Java泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理好一切细节。
在使用泛型的时候,我们只需要指定他们的名称以及类型参数即可。
网友评论