这两天看Java编程思想,重新学习了一下泛型的知识。 以前很多不懂得地方也梳理了一下。
在没有使用泛型之前,我们编写一个类,想要持有其他类型的任何对象。
public class Holder {
private Object a;
public Holder(Object a){
this.a = a;
}
public Object get() {
return a;
}
public void set(Object a) {
this.a = a;
}
public static void main(String[] args) {
Holder h = new Holder(new AutoMobile());
AutoMobile m = (AutoMobile) h.get();
h.set("Not AutoMobile");
String s = (String) h.get();
}
}
class AutoMobile{}
这个例子,我们先后存了两种类型的对象,但是当我们从holder中取出对象的时候,需要强制类型转换才可以。
泛型的主要目的之一就是用来制定容器要持有什么类型的对象,而且编译器来保证类型的正确性。
因此,与其我们用Object,更喜欢暂时不指定类型,而是之后决定使用什么类型,这时候我们需要使用类型参数,下面例子中T就是类型参数。
public class HolderT<T> {
private T t;
public HolderT(T t){
this.t = t;
}
public T get() {
return t;
}
public void set(T t) {
this.t = t;
}
public static void main(String[] args) {
HolderT<AutoMobile> h = new HolderT<AutoMobile>(new AutoMobile());
AutoMobile a = h.get();
// h.set("Not AutoMobile"); 编译器报错,因为我们要制定存储的事AutoMobile类型的对象
HolderT<String> h2 = new HolderT<String>("Not AutoMobile");
String s = h2.get();
}
}
现在当创建HolderT的时候必须指明想要持有的对象,将其置于尖括号中。之后get和set的时候都已经制定了现在持有的对象。
这里初步讲下泛型的基本用法,接下来会写一些我觉的需要注意的泛型的例子和用法。
现在我们实现一个堆栈类。
public class LinedStack<T> {
private static class Node<U>{
U item;
Node next;
Node(){
this.item = null;
this.next = null;
}
Node(U item,Node next){
this.item = item;
this.next = next;
}
boolean end(){
return item == null && next == null;
}
}
private Node<T> top = new Node<T>();
public void push(T item){
top = new Node(item,top);
}
public T pop(){
T result = top.item;
if(!top.end()){
top = top.next;
}
return result;
}
public static void main(String[] args) {
LinedStack<Integer> stack = new LinedStack<Integer>();
stack.push(1);
stack.push(2);
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
这里的Node也是泛型的,他有自己的类型参数U。
这里我们使用了末端哨兵来判断堆栈何时为空。这里我关注的是一点,如果我不给他的内部类Node设定自己的类型参数,而是跟外部的类型参数一样。
如果直接去掉U的类型参数,会报错。这里就需要先说一说类型擦除的概念。这个稍后再说。先让我们看看泛型方法。
之前我们看到的泛型都是作用在类上,但他同样可以作用在方法上。泛型方法使得该方法独立于类而产生变化。以下是一些基本的指导建议:
无论何时,只要你能做到,就应该只使用泛型方法,因为他使得事情更清楚明白,另外,对于一个static的方法而言,无法访问泛型类的泛型类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。
要定义泛型方法,只需要将泛型参数列表置于返回类型之前就可以。
public class GenericMehtods {
public static <T> void f(T t){
System.out.println(t.getClass().getName());
}
public static void main(String[] args) {
f("");
f(1);