Thinking in java4 15章 泛型
1 生成器的妙用
2 Set2的集合,操作。
//: net/mindview/util/Sets.java
package net.mindview.util;
import java.util.*;
public class Sets {
public static <T> Set<T> union(Set<T> a, Set<T> b) {
Set<T> result = new HashSet<T>(a);
result.addAll(b);
return result;
}
public static <T> Set<T> intersection(Set<T> a, Set<T> b) {
Set<T> result = new HashSet<T>(a);
result.retainAll(b);
return result;
}
// Subtract subset from superset:
public static <T> Set<T> difference(Set<T> superset, Set<T> subset) {
Set<T> result = new HashSet<T>(superset);
result.removeAll(subset);
return result;
}
// Reflexive--everything not in the intersection:
public static <T> Set<T> complement(Set<T> a, Set<T> b) {
return difference(union(a, b), intersection(a, b));
}
} // /:~
3 匿名内部类和生成器的使用,构造函数为private
4 复杂数据类型,元祖的集合。方法返回多个数据
//: net/mindview/util/Tuple.java
// Tuple library using type argument inference.
package net.mindview.util;
/**
* @author zhouhanxiu
*
*/
public class Tuple {
public static <A, B> TwoTuple<A, B> tuple(A a, B b) {
return new TwoTuple<A, B>(a, b);
}
public static <A, B, C> ThreeTuple<A, B, C> tuple(A a, B b, C c) {
return new ThreeTuple<A, B, C>(a, b, c);
}
public static <A, B, C, D> FourTuple<A, B, C, D> tuple(A a, B b, C c, D d) {
return new FourTuple<A, B, C, D>(a, b, c, d);
}
public static <A, B, C, D, E> FiveTuple<A, B, C, D, E> tuple(A a, B b, C c,
D d, E e) {
return new FiveTuple<A, B, C, D, E>(a, b, c, d, e);
}
} // /:~
5 擦除原理,编译期间制定类型检查,迁移兼容性折中方式 边界
未指定边界对应Object,客户端代码不用改变。
6 擦除原理,运行时检查,使用isInstance 代替instanceof
7 泛型和工厂设计模式 FactoryConstraint
import java.util.HashMap;
import java.util.Map;
//: generics/Holder.java
public class Holder {
public static class Car {
}
public static class BaoMa extends Car {
}
/**
* 泛型实现工厂方法
*
* @author zhouhanxiu
*
*/
public static abstract class FactoryCreate<T> {
public abstract T createInstance();
}
public static class CarFactory extends FactoryCreate<Car> {
@Override
public Car createInstance() {
try {
return Car.class.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static class BaomaFactory extends FactoryCreate<BaoMa> {
@Override
public BaoMa createInstance() {
try {
return BaoMa.class.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* 限定Car子类的工厂
*
* @param type
* @return
*/
public static Car createCarInstance(Class<? extends Car> type) {
try {
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 所有类的工厂,没有无参构造方法,调用默认构造方法。
*
* @param type
* @return
*/
public static <T> T createByTypeClass(Class<T> type) {
try {
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 泛型单例
*
* @author zhouhanxiu
* @param <T>
*/
public static class SingleFactory<T> {
private static Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
public static synchronized <T> T create(Class<T> type) {
try {
if (!map.containsKey(type))
map.put(type, type.newInstance());
return (T) map.get(type);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
Car c = createByTypeClass(Car.class);
System.out.println(c);
Car bm = createByTypeClass(BaoMa.class);
System.out.println(bm);
Car c1 = createCarInstance(Car.class);
System.out.println(c1);
Car bm2 = createCarInstance(BaoMa.class);
System.out.println(bm2);
CarFactory factory1 = new CarFactory();
Car c11 = factory1.createInstance();
System.out.println(c11);
BaomaFactory factory2 = new BaomaFactory();
Car bm22 = factory2.createInstance();
System.out.println(bm22);
System.out.println(SingleFactory.create(Car.class));
System.out.println(SingleFactory.create(Car.class));
}
} /*
* Output: (Sample) java.lang.ClassCastException: Apple cannot be cast to Orange
* true
*/// :~
8 泛型和模板设计模式 GenericWithCreate
9 数组泛型实际是Object[], GenericArray和GenericArray2
泛型中创建数组 Array.newInstance()
《java谜题》书籍,有时间看看
10 多边界EpicBattle InheritBounds BasicBounds
11 通配符?单一边界。
12 数组和容器在泛型上的区别,
见NonCovariantGenerics和CovariantArrays 数组支持协变,容器为了协变搞了通配符。
13 协变和逆变, Product Extend Consumer Super PECS
14 上届通配符? extends 只能get(多态转换为父类),不能添加。
15 下届通配符 ? super 只能add,不能get(不知道是哪个父类)
16 自动装箱和拆箱,在泛型有一定用处,但不能解决所有问题
见PrimitiveGenericTest和作业Holders30
17 参数化接口问题,导致接口重复实现
见MultipleInterfaceVariants和**HijackedInterface的接口Comparable问题
18 自限定类型 指定自己的类型
只能强制用于继承关系,NotSelfBounded
19 自限定类型,支持协变
20 Collections 动态类型安全
Collections .checkedCollection checkedList, checkedMap,checkedSet,checkSortedMap,checkSortedSet
//: generics/CheckedList.java
// Using Collection.checkedList().
import typeinfo.pets.Cat;
import typeinfo.pets.Pet;
import typeinfo.pets.Dog;
import java.util.*;
public class CheckedList {
@SuppressWarnings("unchecked")
static void oldStyleMethod(List probablyDogs) {
probablyDogs.add(new Cat());
}
public static void main(String[] args) {
List<Dog> dogs1 = new ArrayList<Dog>();
oldStyleMethod(dogs1); // Quietly accepts a Cat
List<Dog> dogs2 = Collections.checkedList(new ArrayList<Dog>(),
Dog.class);
try {
oldStyleMethod(dogs2); // Throws an exception
} catch (Exception e) {
e.printStackTrace();
}
// Derived types work fine:
List<Pet> pets = Collections.checkedList(new ArrayList<Pet>(),
Pet.class);
pets.add(new Dog());
pets.add(new Cat());
}
} /*
* Output: java.lang.ClassCastException: Attempt to insert class
* typeinfo.pets.Cat element into collection with element type class
* typeinfo.pets.Dog
*/// :~
21 泛型应用于异常很受限
catch不能获取E泛型的异常,只能是具体的异常,throws E 可以,见 ThrowGenericException
//: generics/ThrowGenericException.java
import java.util.*;
interface Processor<T, E extends Exception> {
void process(List<T> resultCollector) throws E;
}
class ProcessRunner<T, E extends Exception> extends ArrayList<Processor<T, E>> {
List<T> processAll() throws E {
List<T> resultCollector = new ArrayList<T>();
for (Processor<T, E> processor : this)
processor.process(resultCollector);
return resultCollector;
}
}
class Failure1 extends Exception {
}
class Processor1 implements Processor<String, Failure1> {
static int count = 3;
public void process(List<String> resultCollector) throws Failure1 {
if (count-- > 1)
resultCollector.add("Hep!");
else
resultCollector.add("Ho!");
if (count < 0)
throw new Failure1();
}
}
class Failure2 extends Exception {
}
class Processor2 implements Processor<Integer, Failure2> {
static int count = 2;
public void process(List<Integer> resultCollector) throws Failure2 {
if (count-- == 0)
resultCollector.add(47);
else {
resultCollector.add(11);
}
if (count < 0)
throw new Failure2();
}
}
public class ThrowGenericException {
public static void main(String[] args) {
ProcessRunner<String, Failure1> runner = new ProcessRunner<String, Failure1>();
for (int i = 0; i < 4; i++)
runner.add(new Processor1());
try {
System.out.println(runner.processAll());
} catch (Exception e) {
System.out.println(e);
}
ProcessRunner<Integer, Failure2> runner2 = new ProcessRunner<Integer, Failure2>();
for (int i = 0; i < 3; i++)
runner2.add(new Processor2());
try {
System.out.println(runner2.processAll());
} catch (Exception e) {
System.out.println(e);
}
}
} // /:~
22 动态代理实现混型
//: generics/DynamicProxyMixin.java
import java.lang.reflect.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Tuple.*;
class MixinProxy implements InvocationHandler {
Map<String, Object> delegatesByMethod;
public MixinProxy(TwoTuple<Object, Class<?>>... pairs) {
delegatesByMethod = new HashMap<String, Object>();
for (TwoTuple<Object, Class<?>> pair : pairs) {
for (Method method : pair.second.getMethods()) {
String methodName = method.getName();
// The first interface in the map
// implements the method.
if (!delegatesByMethod.containsKey(methodName))
delegatesByMethod.put(methodName, pair.first);
}
}
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
Object delegate = delegatesByMethod.get(methodName);
return method.invoke(delegate, args);
}
@SuppressWarnings("unchecked")
public static Object newInstance(TwoTuple... pairs) {
Class[] interfaces = new Class[pairs.length];
for (int i = 0; i < pairs.length; i++) {
interfaces[i] = (Class) pairs[i].second;
}
ClassLoader cl = pairs[0].first.getClass().getClassLoader();
return Proxy.newProxyInstance(cl, interfaces, new MixinProxy(pairs));
}
}
public class DynamicProxyMixin {
public static void main(String[] args) {
Object mixin = MixinProxy.newInstance(
tuple(new BasicImp(), Basic.class),
tuple(new TimeStampedImp(), TimeStamped.class),
tuple(new SerialNumberedImp(), SerialNumbered.class));
Basic b = (Basic) mixin;
TimeStamped t = (TimeStamped) mixin;
SerialNumbered s = (SerialNumbered) mixin;
b.set("Hello");
System.out.println(b.get());
System.out.println(t.getStamp());
System.out.println(s.getSerialNumber());
}
} /*
* Output: (Sample) Hello 1132519137015 1
*/// :~
23 潜在类型机制 接口和泛型的优雅结合
SimpleQueue.java
//: generics/SimpleQueue.java
// A different kind of container that is Iterable
import java.util.*;
public class SimpleQueue<T> implements Iterable<T> {
private LinkedList<T> storage = new LinkedList<T>();
public void add(T t) {
storage.offer(t);
}
public T get() {
return storage.poll();
}
public Iterator<T> iterator() {
return storage.iterator();
}
} // /:~
Fill2.java
Addable和生成器接口Generator,适配器模式
//: generics/Fill2.java
// Using adapters to simulate latent typing.
// {main: Fill2Test}
import generics.coffee.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
interface Addable<T> {
void add(T t);
}
public class Fill2 {
public static void main(String[] args) {
// Adapt a Collection:
List<Coffee> carrier = new ArrayList<Coffee>();
Fill2.fill(new AddableCollectionAdapter<Coffee>(carrier), Coffee.class,
3);
// Helper method captures the type:
Fill2.fill(Adapter.collectionAdapter(carrier), Latte.class, 2);
for (Coffee c : carrier)
print(c);
print("----------------------");
// Use an adapted class:
AddableSimpleQueue<Coffee> coffeeQueue = new AddableSimpleQueue<Coffee>();
Fill2.fill(coffeeQueue, Mocha.class, 4);
Fill2.fill(coffeeQueue, Latte.class, 1);
for (Coffee c : coffeeQueue)
print(c);
}
// Classtoken version:
public static <T> void fill(Addable<T> addable,
Class<? extends T> classToken, int size) {
for (int i = 0; i < size; i++)
try {
addable.add(classToken.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Generator version:
public static <T> void fill(Addable<T> addable, Generator<T> generator,
int size) {
for (int i = 0; i < size; i++)
addable.add(generator.next());
}
}
// To adapt a base type, you must use composition.
// Make any Collection Addable using composition:
class AddableCollectionAdapter<T> implements Addable<T> {
private Collection<T> c;
public AddableCollectionAdapter(Collection<T> c) {
this.c = c;
}
public void add(T item) {
c.add(item);
}
}
// A Helper to capture the type automatically:
class Adapter {
public static <T> Addable<T> collectionAdapter(Collection<T> c) {
return new AddableCollectionAdapter<T>(c);
}
}
// To adapt a specific type, you can use inheritance.
// Make a SimpleQueue Addable using inheritance:
class AddableSimpleQueue<T> extends SimpleQueue<T> implements Addable<T> {
public void add(T item) {
super.add(item);
}
}
24 函数对象用作策略设计模式
一种优雅的设计,泛型,函数,策略的结合,适配器模式和策略模式的结合,高中自然科学中数学中的函数和泛型函数的思想联系。
//: generics/Functional.java
import java.math.*;
import java.util.concurrent.atomic.*;
import java.util.*;
import static net.mindview.util.Print.*;
// Different types of function objects:
interface Combiner<T> {
T combine(T x, T y);
}
interface UnaryFunction<R, T> {
R function(T x);
}
interface Collector<T> extends UnaryFunction<T, T> {
T result(); // Extract result of collecting parameter
}
interface UnaryPredicate<T> {
boolean test(T x);
}
public class Functional {
// Calls the Combiner object on each element to combine
// it with a running result, which is finally returned:
public static <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:
return null; // 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.
public static <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:
public static <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":
public static <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:
static class IntegerAdder implements Combiner<Integer> {
public Integer combine(Integer x, Integer y) {
return x + y;
}
}
static class IntegerSubtracter implements Combiner<Integer> {
public Integer combine(Integer x, Integer y) {
return x - y;
}
}
static class BigDecimalAdder implements Combiner<BigDecimal> {
public BigDecimal combine(BigDecimal x, BigDecimal y) {
return x.add(y);
}
}
static class BigIntegerAdder implements Combiner<BigInteger> {
public BigInteger combine(BigInteger x, BigInteger y) {
return x.add(y);
}
}
static class AtomicLongAdder implements Combiner<AtomicLong> {
public AtomicLong combine(AtomicLong x, AtomicLong y) {
// Not clear whether this is meaningful:
return new AtomicLong(x.addAndGet(y.get()));
}
}
// We can even make a UnaryFunction with an "ulp"
// (Units in the last place):
// 最后一位,小时点
static class BigDecimalUlp implements UnaryFunction<BigDecimal, BigDecimal> {
public BigDecimal function(BigDecimal x) {
return x.ulp();
}
}
static class GreaterThan<T extends Comparable<T>> implements
UnaryPredicate<T> {
private T bound;
public GreaterThan(T bound) {
this.bound = bound;
}
public boolean test(T x) {
return x.compareTo(bound) > 0;
}
}
static class MultiplyingIntegerCollector implements Collector<Integer> {
private Integer val = 1;
public Integer function(Integer x) {
val *= x;
return val;
}
public Integer result() {
return val;
}
}
public static void main(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());
print(result);
result = reduce(li, new IntegerSubtracter());
print(result);
print(filter(li, new GreaterThan<Integer>(4)));
print(forEach(li, new MultiplyingIntegerCollector()).result());
print(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());
print(rbd);
print(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();
}
print(lbi);
BigInteger rbi = reduce(lbi, new BigIntegerAdder());
print(rbi);
// The sum of this list of primes is also prime:
// 是否是素数
print(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());
print(ral);
print(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]
*/// :~