publicclass Raw {
// Uses raw type (List) - fails at runtime! - Page 112publicstaticvoidmain(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42));
String s = strings.get(0); // Compiler-generated cast
}
privatestaticvoidunsafeAdd(List list, Object o) {
list.add(o);
}
// Use of raw type for unknown element type - don't do this! - Page 113staticint rawNumElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
//如果要使用泛型,但不确定或者不关心实际的类型参数(如上面的例子),就可以使用一个问好代替。例如,泛型Set<E>的无限制通配符类型为Set<?>(读作“某个类型的集合”)// Unbounded wildcard type - typesafe and flexible - Page 113staticint numElementsInCommon(Set<?> s1, Set<?> s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
}
//为什么说Set<?>是类型安全的:你不能将除了null外的任何元素放入Collection<?>中
interface Function<T> {
T apply(T arg1, T arg2);
}
publicclass Reduction {
static <E> E reduce(List<E> list, Function<E> f, E initVal) {
List<E> snapshot;
synchronized (list) {
snapshot = new ArrayList<E>(list);
}
E result = initVal;
for (E e : snapshot)
result = f.apply(result, e);
return result;
}
// A few sample functionsprivatestatic final Function<Integer> SUM = new Function<Integer>() {
public Integer apply(Integer i1, Integer i2) {
return i1 + i2;
}
};
privatestatic final Function<Integer> PRODUCT = new Function<Integer>() {
public Integer apply(Integer i1, Integer i2) {
return i1 * i2;
}
};
privatestatic final Function<Integer> MAX = new Function<Integer>() {
public Integer apply(Integer i1, Integer i2) {
return Math.max(i1, i2);
}
};
privatestatic final Function<Integer> MIN = new Function<Integer>() {
public Integer apply(Integer i1, Integer i2) {
return Math.min(i1, i2);
}
};
publicstaticvoidmain(String[] args) {
List<Integer> intList = Arrays.asList(2, 7, 1, 8, 2, 8, 1, 8, 2, 8);
// Reduce intList using each of the above reducers
System.out.println(reduce(intList, SUM, 0));
System.out.println(reduce(intList, PRODUCT, 1));
System.out.println(reduce(intList, MAX, Integer.MIN_VALUE));
System.out.println(reduce(intList, MIN, Integer.MAX_VALUE));
}
}
第26条 优先考虑泛型
考虑自己编写一个带泛型的Stack,第一种:
publicclass EmptyStackException extends RuntimeException {
}
publicclass Stack<E> {
private E[] elements;
privateint size = 0;
privatestatic final int DEFAULT_INITIAL_CAPACITY = 16;
// The elements array will contain only E instances from push(E).// This is sufficient to ensure type safety, but the runtime// type of the array won't be E[]; it will always be Object[]!
@SuppressWarnings("unchecked")
publicStack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
publicvoidpush(E e) {
ensureCapacity();
elements[size++] = e;
}
public E pop() {
if (size == 0)
thrownew EmptyStackException();
E result = elements[--size];
elements[size] = null; // Eliminate obsolete referencereturn result;
}
public boolean isEmpty() {
return size == 0;
}
privatevoidensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
// Little program to exercise our generic Stackpublicstaticvoidmain(String[] args) {
Stack<String> stack = new Stack<String>();
for (String arg : args)
stack.push(arg);
while (!stack.isEmpty())
System.out.println(stack.pop().toUpperCase());
}
}
第二种:
publicclass EmptyStackException extends RuntimeException {
}
publicclass Stack<E> {
private Object[] elements;
privateint size = 0;
privatestatic final int DEFAULT_INITIAL_CAPACITY = 16;
publicStack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
publicvoidpush(E e) {
ensureCapacity();
elements[size++] = e;
}
// Appropriate suppression of unchecked warningpublic E pop() {
if (size == 0)
thrownew EmptyStackException();
// push requires elements to be of type E, so cast is correct
@SuppressWarnings("unchecked")
E result = (E) elements[--size];
elements[size] = null; // Eliminate obsolete referencereturn result;
}
public boolean isEmpty() {
return size == 0;
}
privatevoidensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
// Little program to exercise our generic Stackpublicstaticvoidmain(String[] args) {
Stack<String> stack = new Stack<String>();
for (String arg : args)
stack.push(arg);
while (!stack.isEmpty())
System.out.println(stack.pop().toUpperCase());
}
}
publicinterface UnaryFunction<T> {
T apply(T arg);
}
现在假设要提供一个恒等函数(identity function)(一个函数对象).可以这样:
publicclass GenericSingletonFactory {
// Generic singleton factory patternprivatestatic UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {
public Object apply(Object arg) {
return arg;
}
};
// IDENTITY_FUNCTION is stateless and its type parameter is// unbounded so it's safe to share one instance across all types.
@SuppressWarnings("unchecked")
publicstatic <T> UnaryFunction<T> identityFunction() {
return (UnaryFunction<T>) IDENTITY_FUNCTION;
}
// Sample program to exercise generic singletonpublicstaticvoidmain(String[] args) {
String[] strings = { "jute", "hemp", "nylon" };
UnaryFunction<String> sameString = identityFunction();
for (String s : strings)
System.out.println(sameString.apply(s));
Number[] numbers = { 1, 2.0, 3L };
UnaryFunction<Number> sameNumber = identityFunction();
for (Number n : numbers)
System.out.println(sameNumber.apply(n));
}
}
递归类型限制:
publicclass RecursiveTypeBound {
// Returns the maximum value in a list - uses recursive type boundpublicstatic <T extends Comparable<T>> T max(List<T> list) {
Iterator<T> i = list.iterator();
T result = i.next();
while (i.hasNext()) {
T t = i.next();
if (t.compareTo(result) > 0)
result = t;
}
return result;
}
publicstaticvoidmain(String[] args) {
List<String> argList = Arrays.asList(args);
System.out.println(max(argList));
}
}
第28条 利用有限制通配符来提升API灵活性
如25条所述,参数化类型是不可变的(invariant),这样如果我们有:
publicclass Stack<E>{
publicStack();
publicvoidpush(E e);
public E pop();
public boolean isEmpty();
}
然后我们想要增加一个方法,让它按顺序将一系列的元素全部放到堆栈中,如下:
//pushAll method withod wildcard type - dificient!publicvoidpushAll(Iterable<E> src){
for(E e :src)
push(e);
}
publicclass EmptyStackException extends RuntimeException {
}
publicclass Stack<E> {
private E[] elements;
privateint size = 0;
privatestatic final int DEFAULT_INITIAL_CAPACITY = 16;
// The elements array will contain only E instances from push(E).// This is sufficient to ensure type safety, but the runtime// type of the array won't be E[]; it will always be Object[]!
@SuppressWarnings("unchecked")
publicStack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
publicvoidpush(E e) {
ensureCapacity();
elements[size++] = e;
}
public E pop() {
if (size == 0)
thrownew EmptyStackException();
E result = elements[--size];
elements[size] = null; // Eliminate obsolete referencereturn result;
}
public boolean isEmpty() {
return size == 0;
}
privatevoidensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
// pushAll method without wildcard type - deficient!// public void pushAll(Iterable<E> src) {// for (E e : src)// push(e);// }// Wildcard type for parameter that serves as an E producerpublicvoidpushAll(Iterable<? extends E> src) {
for (E e : src)
push(e);
}
// popAll method without wildcard type - deficient!// public void popAll(Collection<E> dst) {// while (!isEmpty())// dst.add(pop());// }// Wildcard type for parameter that serves as an E consumerpublicvoidpopAll(Collection<? super E> dst) {
while (!isEmpty())
dst.add(pop());
}
// Little program to exercise our generic Stackpublicstaticvoidmain(String[] args) {
Stack<Number> numberStack = new Stack<Number>();
Iterable<Integer> integers = Arrays.asList(3, 1, 4, 1, 5, 9);
numberStack.pushAll(integers);
Collection<Object> objects = new ArrayList<Object>();
numberStack.popAll(objects);
System.out.println(objects);
}
}
interfaceFunction<T> {
T apply(T arg1, T arg2);
}
publicclassReduction {// Wildcard type for parameter that serves as an E producerstatic <E> E reduce(List<? extends E> list, Function<E> f, EinitVal) {List<E> snapshot;
synchronized (list) {
snapshot = new ArrayList<E>(list);
}
E result = initVal;
for (E e : snapshot)
result = f.apply(result, e);
return result;
}
privatestaticfinalFunction<Number> MAX = newFunction<Number>() {public Number apply(Number n1, Number n2) {
return Double.compare(n1.doubleValue(), n2.doubleValue()) > 0 ? n1
: n2;
}
};
publicstatic void main(String[] args) {
// We can use a Number functionto reduce a list of Integer or DoubleList<Integer> intList = Arrays.asList(2, 7, 1, 8, 2, 8, 1, 8, 2, 8);
System.out.println(reduce(intList, MAX, Integer.MIN_VALUE));
List<Double> doubleList = Arrays.asList(2.718281828, 3.141592654,
1.61803399);
System.out.println(reduce(doubleList, MAX, Double.NEGATIVE_INFINITY));
}
}
publicclass Union {
publicstatic <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {
Set<E> result = new HashSet<E>(s1);
result.addAll(s2);
return result;
}
// Simple program to exercise flexible generic methodpublicstaticvoidmain(String[] args) {
Set<Integer> integers = new HashSet<Integer>();
integers.add(1);
integers.add(3);
integers.add(5);
Set<Double> doubles = new HashSet<Double>();
doubles.add(2.0);
doubles.add(4.0);
doubles.add(6.0);
// Won't compile; see page 137// Set<Number> numbers = union(integers, doubles);// Explicit type parameter is necessary here
Set<Number> numbers = Union.<Number> union(integers, doubles);//这里虽然编译器对泛型方法使用了类型推导,但这里编译器无法推导出E到底是什么,所以要给他一个显式的类型参数
System.out.println(numbers);
}
}
publicclass RecursiveTypeBound {
publicstatic <T extends Comparable<? super T>> T max(List<? extends T> list) {
Iterator<? extends T> i = list.iterator();
T result = i.next();
while (i.hasNext()) {
T t = i.next();
if (t.compareTo(result) > 0)
result = t;
}
return result;
}
publicstaticvoidmain(String[] args) {
List<String> argList = Arrays.asList(args);
System.out.println(max(argList));
}
}
Comparable是T的消费者,因为Comparable消费T并产生一个代表顺序关系的整值
publicclass Swap {
publicstaticvoidswap(List<?> list, int i, int j) {
swapHelper(list, i, j);
}
// Private helper method for wildcard captureprivatestatic <E> voidswapHelper(List<E> list, int i, int j) {
list.set(i, list.set(j, list.get(i)));
}
publicstaticvoidmain(String[] args) {
// Swap the first and last argument and print the resulting list
List<String> argList = Arrays.asList(args);
swap(argList, 0, argList.size() - 1);
System.out.println(argList);
}
}