classCovariantArrays{ publicstaticvoidmain(String[] args){ Fruit[] fruit = new Apple[10]; fruit[0] = new Apple(); // OK fruit[1] = new Jonathan(); // OK // Runtime type is Apple[], not Fruit[] or Orange[]: try { // Compiler allows you to add Fruit: // 运行时抛出异常,此时的数组机制知道它处理的是Apple[] fruit[0] = new Fruit(); // ArrayStoreException } catch(Exception e) { System.out.println(e); } try { // Compiler allows you to add Oranges: fruit[0] = new Orange(); // ArrayStoreException } catch(Exception e) { System.out.println(e); } } } /* Output: java.lang.ArrayStoreException: Fruit java.lang.ArrayStoreException: Orange *///:~
classGenericsAndCovariance{ publicstaticvoidmain(String[] args){ // Wildcards allow covariance: // List<? extends Fruit>:具有任何从Fruit继承的类型的列表,但是为了向上转型为flist,这个类型是什么并没有人关心 // 怎样才能安全地向其中添加对象呢? List<? extends Fruit> flist = new ArrayList<Apple>(); // Compile Error: can't add any type of object: // flist.add(new Apple()); // flist.add(new Fruit()); 即使 创建 flist的时候使用 new ArrayList<Fruit>(); 也不可以成功添加 // flist.add(new Object()); flist.add(null); // Legal but uninteresting // We know that it returns at least Fruit: 可以向上转型为父类 Fruit f = flist.get(0); } }
10.1、编译器有多聪明
使用了 ? extends Fruit 的泛型的方法参数,将不能传入任何具体的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classCompilerIntelligence{ publicstaticvoidmain(String[] args){ // 声明了 List<? extends Fruit> ,编译器不能了解这里需要Fruit的哪个具体子类型,因此不会接受任何类型的Fruit, // add()方法的参数就变成了“? extends Fruit”,不能加入任何的元素 List<? extends Fruit> flist = Arrays.asList(new Apple()); // 但是却可以进行转型 Apple a = (Apple)flist.get(0); // No warning // contains 和 indexOf方法参数类型是Object,因此不涉及任何通配符,编译器允许这个调用。 // 这意味着将由泛型类的设计者来决定哪些调用时安全的,并使用Object类型作为其参数类型 flist.contains(new Apple()); // Argument is 'Object' flist.indexOf(new Apple()); // Argument is 'Object' } }
classGenericWriting{ static <T> voidwriteExact(List<T> list, T item){ list.add(item); } static List<Apple> apples = new ArrayList<Apple>(); static List<Fruit> fruit = new ArrayList<Fruit>(); staticvoidf1(){ writeExact(apples, new Apple()); // writeExact(fruit, new Apple()); // Error: // Incompatible types: found Fruit, required Apple } static <T> voidwriteWithWildcard(List<? super T> list, T item){ list.add(item); } staticvoidf2(){ writeWithWildcard(apples, new Apple()); // 使用超类型边界之后,可以把Apple添加到类型为Fruit的list中了 writeWithWildcard(fruit, new Apple()); } publicstaticvoidmain(String[] args){ f1(); f2(); } }
classGenericReading{ // readExact使用了精确类型 static <T> T readExact(List<T> list){ return list.get(0); } static List<Apple> apples = Arrays.asList(new Apple()); static List<Fruit> fruit = Arrays.asList(new Fruit()); // A static method adapts to each call: staticvoidf1(){ Apple a = readExact(apples); Fruit f = readExact(fruit); f = readExact(apples); } // 如果有一个泛型类,当你创建这个类的实例时,要为这个类确定参数,就像在f2()中看到的,确定了类型后,就不能传递其他类型 的参数了。 staticclassReader<T> { T readExact(List<T> list){ return list.get(0); } } staticvoidf2(){ Reader<Fruit> fruitReader = new Reader<Fruit>(); Fruit f = fruitReader.readExact(fruit); // Fruit a = fruitReader.readExact(apples); // Error: // readExact(List<Fruit>) cannot be // applied to (List<Apple>). } // 为了解决这个问题,可以考虑使用子类型边界(向上转换为T,超类边界是为了让具体的子类可用) staticclassCovariantReader<T> { T readCovariant(List<? extends T> list){ return list.get(0); } } staticvoidf3(){ CovariantReader<Fruit> fruitReader = new CovariantReader<Fruit>(); Fruit f = fruitReader.readCovariant(fruit); Fruit a = fruitReader.readCovariant(apples); } publicstaticvoidmain(String[] args){ f1(); f2(); f3(); } } ///:~
classWildcards{ // Raw argument: // Holder是一个泛型类,这里表示称原生类型,但是编译器仍就知道向set传递一个Object是不安全的。 staticvoidrawArgs(Holder holder, Object arg){ // holder.set(arg); // Warning: // Unchecked call to set(T) as a // member of the raw type Holder // holder.set(new Wildcards()); // Same warning
// Can't do this; don't have any 'T': // T t = holder.get(); // OK, but type information has been lost: Object obj = holder.get(); } // Similar to rawArgs(), but errors instead of warnings: // 这里演示了<?>和原生类型是不同的: staticvoidunboundedArg(Holder<?> holder, Object arg){ // 原生Holder将持有任何类型的组合,而Holder<?>将持有具有某种具体类型的同构集合,因此不能只是向其中传递Object holder.set(arg); // Error: // set(capture of ?) in Holder<capture of ?> // cannot be applied to (Object) // holder.set(new Wildcards()); // Same error
// Can't do this; don't have any 'T': // T t = holder.get(); // OK, but type information has been lost: Object obj = holder.get(); } static <T> T exact1(Holder<T> holder){ T t = holder.get(); return t; } static <T> T exact2(Holder<T> holder, T arg){ holder.set(arg); T t = holder.get(); return t; } // 在Holder类型上的限制被放松为包括持有任何扩展自T的对象的Holder, // 传入了Holder<Apple>之后,为了防止将Orange放置到Holder<Apple>, // 对set的调用都是不允许的,但是你仍旧知道任何来自Holder<? extends Fruit的对象至少是Fruit,因此get()是允许的 static <T> T wildSubtype(Holder<? extends T> holder, T arg){ // holder.set(arg); // Error: // set(capture of ? extends T) in // Holder<capture of ? extends T> // cannot be applied to (T) T t = holder.get(); return t; } // 展示超类型通配 static <T> voidwildSupertype(Holder<? super T> holder, T arg){ // holder可以是持有任何T的基类型的容器,因此,set()可以接受T,因为任何可以工作于基类的对象都可以多态地作用于导出类(这里就是T) holder.set(arg); // T t = holder.get(); // Error: 由holder持有的类型可以是任何超类型,因此唯一安全的类型就是Object // Incompatible types: found Object, required T
// OK, but type information has been lost: Object obj = holder.get(); } publicstaticvoidmain(String[] args){ Holder raw = new Holder<Long>(); // Or: raw = new Holder(); Holder<Long> qualified = new Holder<Long>(); Holder<?> unbounded = new Holder<Long>(); Holder<? extends Long> bounded = new Holder<Long>(); Long lng = 1L;
rawArgs(raw, lng); rawArgs(qualified, lng); rawArgs(unbounded, lng); rawArgs(bounded, lng); unboundedArg(raw, lng); unboundedArg(qualified, lng); unboundedArg(unbounded, lng); unboundedArg(bounded, lng); // Object r1 = exact1(raw); // Warnings: // Unchecked conversion from Holder to Holder<T> // Unchecked method invocation: exact1(Holder<T>) // is applied to (Holder) Long r2 = exact1(qualified); Object r3 = exact1(unbounded); // Must return Object Long r4 = exact1(bounded); // Long r5 = exact2(raw, lng); // Warnings: // Unchecked conversion from Holder to Holder<Long> // Unchecked method invocation: exact2(Holder<T>,T) // is applied to (Holder,Long) Long r6 = exact2(qualified, lng); // Long r7 = exact2(unbounded, lng); // Error: // exact2(Holder<T>,T) cannot be applied to // (Holder<capture of ?>,Long) // Long r8 = exact2(bounded, lng); // Error: // exact2(Holder<T>,T) cannot be applied // to (Holder<capture of ? extends Long>,Long) // Long r9 = wildSubtype(raw, lng); // Warnings: // Unchecked conversion from Holder // to Holder<? extends Long> // Unchecked method invocation: // wildSubtype(Holder<? extends T>,T) is // applied to (Holder,Long) Long r10 = wildSubtype(qualified, lng); // OK, but can only return Object: Object r11 = wildSubtype(unbounded, lng); Long r12 = wildSubtype(bounded, lng); // wildSupertype(raw, lng); // Warnings: // Unchecked conversion from Holder // to Holder<? super Long> // Unchecked method invocation: // wildSupertype(Holder<? super T>,T) // is applied to (Holder,Long) wildSupertype(qualified, lng); // wildSupertype(unbounded, lng); // Error: // wildSupertype(Holder<? super T>,T) cannot be // applied to (Holder<capture of ?>,Long) // wildSupertype(bounded, lng); // Error: // wildSupertype(Holder<? super T>,T) cannot be // applied to (Holder<capture of ? extends Long>,Long) } }
classFixedSizeStack<T> { privateint index = 0; private Object[] storage; publicFixedSizeStack(int size){ storage = new Object[size]; } publicvoidpush(T item){ storage[index++] = item; } @SuppressWarnings("unchecked") public T pop(){ // 转型 unchecked cast警告,由于擦除的原因,编译器无法知道这个转型是否安全 // 实际上只是将Object转型为Object return (T)storage[--index]; } }
publicclassChapter15_11_3{ publicstaticfinalint SIZE = 10; publicstaticvoidmain(String[] args){ FixedSizeStack<String> strings = new FixedSizeStack<String>(SIZE); for(String s : "A B C D E F G H I J".split(" ")) strings.push(s); for(int i = 0; i < SIZE; i++) { String s = strings.pop(); System.out.print(s + " "); } }
@SuppressWarnings("unchecked") publicvoidf(String filepath)throws Exception{ // 下面演示由readObject()方法读取转型 ObjectInputStream in = new ObjectInputStream(new FileInputStream(filepath)); // 如果没有压制的注解,则会阐释警告 Unchecked cast from Object to List<Circle> // List<Circle> circles = (List<Circle>)in.readObject(); // 如果想继续使用泛型的情况下不产生警告,则可以使用Java EE5中的使用泛型类来转型 List<Circle> circles = List.class.cast(in.readObject()); // 但是你继续添加如下转型是仍会得到一个警告 // Type safety: Unchecked cast from List to List<Circle> circles = (List<Circle>)List.class.cast(in.readObject()); } } ```java ### 11.4、重载
由于擦除的原因,重载方法将产生相同的类型签名 ```java classUseList<W,T> { // 错误:Method f(List<T>) has the same erasure f(List<E>) as another method in type UseList<W,T> voidf(List<T> v){} voidf(List<W> v){} }
classComparablePetimplementsComparable<ComparablePet> { publicintcompareTo(ComparablePet arg){ return0; } } // 报错:The interface Comparable cannot be implemented more than once with different arguments: // Comparable<ComparablePet> and Comparable<TomCat> // 基类ComparablePet劫持了Comparable接口,只能进行ComparablePet的比较,而不能进行TomCat的比较 classTomCatextendsComparablePetimplementsComparable<TomCat>{ // Error: Comparable cannot be inherited with // different arguments: <Cat> and <Pet> publicintcompareTo(TomCat arg){ return0; } }
classUnconstrained{ publicstaticvoidmain(String[] args){ BasicOther b = new BasicOther(), b2 = new BasicOther(); b.set(new Other()); Other other = b.get(); b.f(); } }
classSelfBounded<TextendsSelfBounded<T>> { T element; SelfBounded<T> set(T arg){ element = arg; returnthis; } T get(){ return element; } }
classAextendsSelfBounded<A> {} classBextendsSelfBounded<A> {} // Also OK
classCextendsSelfBounded<C> { C setAndGet(C arg){ set(arg); return get(); } }
classD{} // Can't do this: // class E extends SelfBounded<D> {} // Compile error: Type parameter D is not within its bound
// Alas, you can do this, so you can't force the idiom: classFextendsSelfBounded{}
publicclassChapter15_12_2{ publicstaticvoidmain(String[] args){ A a = new A();
// 直接使用SelfBounded,传入类似A这样的子类 SelfBounded<A> bounded = new SelfBounded<A>(); a.set(new A()); a = a.set(new A()).get(); a = a.get(); C c = new C(); c = c.setAndGet(new C()); } }
还可以将自限定用于泛型方法
1 2 3 4 5 6 7 8
classSelfBoundingMethods{ static <T extends SelfBounded<T>> T f(T arg){ return arg.set(arg).get(); } publicstaticvoidmain(String[] args){ A a = f(new A()); } }
classOrdinaryArguments{ publicstaticvoidmain(String[] args){ Base base = new Base(); Derived derived = new Derived(); DerivedSetter ds = new DerivedSetter(); ds.set(derived); ds.set(base); // 这里ds实际上有两个方法,在继承的时候,set方法被重载了,而不是覆盖了。 } }
publicclassChapter15_12_3{ publicstaticvoidmain(String[] args){ Base base = new Base(); Derived derived = new Derived(); DerivedGS dgs = new DerivedGS(); dgs.set(derived); dgs.set(base); // 编译通过,DerivedGS中的set()方法被重载,非覆盖 } }
classDecoration{ publicstaticvoidmain(String[] args){ TimeStamped t = new TimeStamped(new Basic()); TimeStamped t2 = new TimeStamped( new SerialNumbered(new Basic())); //! t2.getSerialNumber(); // Not available SerialNumbered s = new SerialNumbered(new Basic()); SerialNumbered s2 = new SerialNumbered( new TimeStamped(new Basic())); //! s2.getStamp(); // Not available } }
// To adapt a base type, you must use composition. // Make any Collection Addable using composition: // 创建一个Collection的Addable适配器 classAddableCollectionAdapter<T> implementsAddable<T> { private Collection<T> c; publicAddableCollectionAdapter(Collection<T> c){ this.c = c; } publicvoidadd(T item){ c.add(item); } }
// A Helper to capture the type automatically: classAdapter{ publicstatic <T> Addable<T> collectionAdapter(Collection<T> c){ returnnew AddableCollectionAdapter<T>(c); } }
// To adapt a specific type, you can use inheritance. // Make a SimpleQueue Addable using inheritance: classAddableSimpleQueue<T> extendsSimpleQueue<T> implementsAddable<T> { publicvoidadd(T item){ super.add(item); } }
//Different types of function objects: // 运算法则:联合 interfaceCombiner<T> { T combine(T x, T y); } // 单参函数 interfaceUnaryFunction<R,T> { R function(T x); } // 收集器 interfaceCollector<T> extendsUnaryFunction<T,T> { T result(); // Extract result of collecting parameter } // interfaceUnaryPredicate<T> { booleantest(T x); }
classFunctional{ // 结合seq中的所有对象 publicstatic <T> T reduce(Iterable<T> seq, Combiner<T> combiner){ Iterator<T> it = seq.iterator(); if(it.hasNext()) { T result = it.next(); while(it.hasNext()) result = combiner.combine(result, it.next()); return result; } // If seq is the empty list: returnnull; // Or throw exception } // Take a function object and call it on each object in // the list, ignoring the return value. The function // object may act as a collecting parameter, so it is // returned at the end. publicstatic <T> Collector<T> forEach(Iterable<T> seq, Collector<T> func){ for(T t : seq) func.function(t); return func; } // Creates a list of results by calling a // function object for each object in the list: publicstatic <R,T> List<R> transform(Iterable<T> seq, UnaryFunction<R,T> func){ List<R> result = new ArrayList<R>(); for(T t : seq) result.add(func.function(t)); return result; } // Applies a unary predicate to each item in a sequence, // and returns a list of items that produced "true": publicstatic <T> List<T> filter(Iterable<T> seq, UnaryPredicate<T> pred){ List<T> result = new ArrayList<T>(); for(T t : seq) if(pred.test(t)) result.add(t); return result; } // To use the above generic methods, we need to create // function objects to adapt to our particular needs: staticclassIntegerAdderimplementsCombiner<Integer> { public Integer combine(Integer x, Integer y){ return x + y; } } staticclassIntegerSubtracterimplementsCombiner<Integer> { public Integer combine(Integer x, Integer y){ return x - y; } } staticclassBigDecimalAdderimplementsCombiner<BigDecimal> { public BigDecimal combine(BigDecimal x, BigDecimal y){ return x.add(y); } } staticclassBigIntegerAdderimplementsCombiner<BigInteger> { public BigInteger combine(BigInteger x, BigInteger y){ return x.add(y); } } staticclassAtomicLongAdderimplementsCombiner<AtomicLong> { public AtomicLong combine(AtomicLong x, AtomicLong y){ // Not clear whether this is meaningful: returnnew AtomicLong(x.addAndGet(y.get())); } } // We can even make a UnaryFunction with an "ulp" // (Units in the last place): staticclassBigDecimalUlpimplementsUnaryFunction<BigDecimal,BigDecimal> { public BigDecimal function(BigDecimal x){ return x.ulp(); } } staticclassGreaterThan<TextendsComparable<T>> implementsUnaryPredicate<T> { private T bound; publicGreaterThan(T bound){ this.bound = bound; } publicbooleantest(T x){ return x.compareTo(bound) > 0; } } staticclassMultiplyingIntegerCollectorimplementsCollector<Integer> { private Integer val = 1; public Integer function(Integer x){ val *= x; return val; } public Integer result(){ return val; } } publicstaticvoidmain(String[] args){ // Generics, varargs & boxing working together: List<Integer> li = Arrays.asList(1, 2, 3, 4, 5, 6, 7); Integer result = reduce(li, new IntegerAdder()); System.out.println(result);
result = reduce(li, new IntegerSubtracter()); System.out.println(result); System.out.println(filter(li, new GreaterThan<Integer>(4))); System.out.println(forEach(li, new MultiplyingIntegerCollector()).result()); System.out.println(forEach(filter(li, new GreaterThan<Integer>(4)), new MultiplyingIntegerCollector()).result()); MathContext mc = new MathContext(7); List<BigDecimal> lbd = Arrays.asList( new BigDecimal(1.1, mc), new BigDecimal(2.2, mc), new BigDecimal(3.3, mc), new BigDecimal(4.4, mc)); BigDecimal rbd = reduce(lbd, new BigDecimalAdder()); System.out.println(rbd); System.out.println(filter(lbd, new GreaterThan<BigDecimal>(new BigDecimal(3)))); // Use the prime-generation facility of BigInteger: List<BigInteger> lbi = new ArrayList<BigInteger>(); BigInteger bi = BigInteger.valueOf(11); for(int i = 0; i < 11; i++) { lbi.add(bi); bi = bi.nextProbablePrime(); } System.out.println(lbi); BigInteger rbi = reduce(lbi, new BigIntegerAdder()); System.out.println(rbi); // The sum of this list of primes is also prime: System.out.println(rbi.isProbablePrime(5)); List<AtomicLong> lal = Arrays.asList( new AtomicLong(11), new AtomicLong(47), new AtomicLong(74), new AtomicLong(133)); AtomicLong ral = reduce(lal, new AtomicLongAdder()); System.out.println(ral); System.out.println(transform(lbd,new BigDecimalUlp())); } } /* Output: 28 -26 [5, 6, 7] 5040 210 11.000000 [3.300000, 4.400000] [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] 311 true 265 [0.000001, 0.000001, 0.000001, 0.000001] *///:~