Java泛型(1):概述
通常而言,我们使用一种容器来存储一种类型的对象。而泛型的主要目的之一就是用来指定这个容器要持有什么类型的对象。因此,与其使用Object,我们可以暂时不指定类型。
看下面3个例子:
(1) 我们有时候想调用一个方法返回多个返回值,但是又不想单独再创建一个类。我们可以将一组对象直接打包放在一个元组中。这个容器处始化后,只允许读取其中元素,不能再写入(final域)。
1 public class TwoTuple<A, B> { 2 public final A first; 3 public final B second; 4 5 public TwoTuple(A first, B second) { 6 this.first = first; 7 this.second = second; 8 } 9 }
1 public class ThreeTuple<A, B, C> extends TwoTuple<A, B> { 2 public final C third; 3 4 public ThreeTuple(A first, B second, C third) { 5 super(first, second); 6 this.third = third; 7 } 8 }
1 public class TupleUtils { 2 3 public static <A, B> TwoTuple<A, B> initTuple(A a, B b) { 4 return new TwoTuple<A, B>(a, b); 5 } 6 7 public static <A, B, C> ThreeTuple<A, B, C> initTuple(A a, B b, C c) { 8 return new ThreeTuple<A, B, C>(a, b, c); 9 } 10 // four five ... 11 }
Main方法测试:
1 TwoTuple<Integer, String> twoTuple = TupleUtils.initTuple(1, "aaa"); 2 ThreeTuple<Integer, String, String> threeTuple = TupleUtils.initTuple(2, "bb", "cc"); 3 System.out.println(twoTuple.first + "/" + twoTuple.second); // 1/aaa 4 System.out.println(threeTuple.first + "/" + threeTuple.second + "/" + threeTuple.third); // 2/bb/cc
(2) 一个自己实现的泛型堆栈例子(模拟链表实现)
1 public class LinkStack<T> { 2 private class Node<U> { 3 U item; 4 Node<U> next; // 相当于一个指针 5 6 Node() { 7 } 8 9 Node(U item, Node<U> next) { 10 this.item = item; 11 this.next = next; 12 } 13 14 boolean isEnd() { 15 return item == null && next == null; 16 } 17 } 18 19 // 末断哨兵,这个指针总是指向栈顶 20 private Node<T> top = new Node<T>(); 21 22 public LinkStack<T> push(T item) { 23 top = new Node<T>(item, top); 24 return this; 25 } 26 27 public T pop() { 28 T result = top.item; 29 if (!top.isEnd()) { 30 top = top.next; 31 } 32 return result; 33 } 34 }
Main方法测试:
1 LinkStack<Integer> stack = new LinkStack<>(); 2 stack.push(1).push(2).push(3); 3 System.out.println(stack.pop() + "/" + stack.pop() + "/" + stack.pop() + "/" + stack.pop()); // 3/2/1/null
(3) 一个随机取对象的容器类
1 public class RandomList<T> { 2 3 public final List<T> storage; 4 5 private Random ran; 6 7 public RandomList(List<T> storage) { 8 if (storage == null || storage.size() == 0) { 9 throw new RuntimeException("List must not be empty!"); 10 } 11 this.storage = storage; 12 // 不设定种子。种子相同,即使实例不同也产生相同的随机数。 13 ran = new Random(); 14 } 15 16 public T select() { 17 if (storage.size() == 0) { 18 return null; 19 } 20 // 随机的int值,介于[0,n)的区间 21 int pos = ran.nextInt(storage.size()); 22 T result = storage.get(pos); 23 storage.remove(pos); 24 return result; 25 } 26 }
Main方法测试:
1 // Arrays.asLisvt()返回java.util.Arrays$ArrayList,而不是ArrayList。 2 // Arrays$ArrayList和ArrayList都是继承AbstractList,但是remove,add等method在AbstractList中是默认throw UnsupportedOperationException。 3 // 所以不能用以下写法。 4 // List<Integer> dataList = Arrays.asList(1, 2, 3, 4, 5); 5 List<Integer> dataList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); 6 RandomList<Integer> ranList = new RandomList<>(dataList); 7 System.out.println(ranList.select() + "/" + ranList.select() + "/" + ranList.select() + "/" + ranList.select() 8 + "/" + ranList.select() + "/" + ranList.select()); // 4/2/5/3/1/null(一种结果)