最近在看THINKING JAVA 的泛型,这本书看了一半,花了最多时间看的就是这个泛型了,感觉蛮复杂的,要创造出适用性广的泛化代码,真的不是容易,而且还没碰到过一个需要这种复杂的场景!
在这章最后作者拿了c++的泛型来和JAVA的泛型作出对比。
首先说说潜在类型机制是神马?“我不关心我在这里使用的类型,只要他具有这些方法即可”。
看看C++怎么实现的:
class Dog {
public:
void speak() {}
void sit() {}
void reproduce() {}
};
class Robot {
public:
void speak() {}
void sit() {}
void oilChange() {
};
template<class T> void perform(T anything) {
anything.speak();
anything.sit();
}
int main() {
Dog d;
Robot r;
perform(d);
perform(r);
} ///:~
而JAVA是这样实现的:
public interface Performs {
void speak();
void sit();
} ///:~
class PerformingDog extends Dog implements Performs {
public void speak() { System.out.println("Woof!"); }
public void sit() { System.out.println("Sitting"); }
public void reproduce() {}
}
class Robot implements Performs {
public void speak() { System.out.println("Click!"); }
public void sit() { System.out.println("Clank!"); }
public void oilChange() {}
}
//这里就看出不同了,T的上边界是Performs接口
class Communicate {
public static <T extends Performs>
void perform(T performer) {
performer.speak();
performer.sit();
}
}
public class DogsAndRobots {
public static void main(String[] args) {
PerformingDog d = new PerformingDog();
Robot r = new Robot();
Communicate.perform(d);
Communicate.perform(r);
}
} /* Output:
Woof!
Sitting
Click!
Clank!
*///:~
从这两段代码可以看出,C++的泛型实现就是潜在类型机制,而JAVA必须在使用泛型时候设定他的上边界“T extends Performs”,我们完全可以这样实现的:
//: generics/SimpleDogsAndRobots.java
// Removing the generic; code still works.
class CommunicateSimply {
static void perform(Performs performer) {
performer.speak();
performer.sit();
}
}
public class SimpleDogsAndRobots {
public static void main(String[] args) {
CommunicateSimply.perform(new PerformingDog());
CommunicateSimply.perform(new Robot());
}
} /* Output:
Woof!
Sitting
Click!
Clank!
*///:~
从这个例子来看,泛型不是必须的,并且JAVA必须制定泛型的边界,如果我需要使用Performs来做边界,感觉就像上面那个例子一样,直接使用Performs好了,而潜在类型机制的概念“我不关心我在这里使用的类型,只要他具有这些方法即可”,在这里JAVA就没办法像C++那样了。
而在本书中提及了,JAVA对潜在类型机制的一些补偿方法:
1、反射
// Using Reflection to produce latent typing.
import java.lang.reflect.Method;
// Does not implement Performs:
class Mime {
public void walkAgainstTheWind() {}
public void sit() { System.out.println("Pretending to sit"); }
public void pushInvisibleWalls() {}
public String toString() { return "Mime"; }
}
// Does not implement Performs:
class SmartDog {
public void speak() { System.out.println("Woof!"); }
public void sit() { System.out.println("Sitting"); }
public void reproduce() {}
}
class CommunicateReflectively {
public static void perform(Object speaker) {
Class<?> spkr = speaker.getClass();
try {
try {
Method speak = spkr.getMethod("speak");
speak.invoke(speaker);
} catch(NoSuchMethodException e) {
System.out.println(speaker + " cannot speak");
}
try {
Method sit = spkr.getMethod("sit");
sit.invoke(speaker);
} catch(NoSuchMethodException e) {
System.out.println(speaker + " cannot sit");
}
} catch(Exception e) {
throw new RuntimeException(speaker.toString(), e);
}
}
}
public class LatentReflection {
public static void main(String[] args) {
CommunicateReflectively.perform(new SmartDog());
CommunicateReflectively.perform(new Robot());
CommunicateReflectively.perform(new Mime());
}
} /* Output:
Woof!
Sitting
Click!
Clank!
Mime cannot speak
Pretending to sit
*///:~
使用反射后就类似c++那个例子了,但是这里没有使用到java的泛型,而且为了这样搞到好复杂,他奶奶的
2、用适配器仿真潜在类型机制
import java.util.Collection;
import t4j.net.mindview.util.Generator;
//接口
interface Addable<T> {
void add(T t);
}
//类生成器
public class Fill2 {
//利用发射来生成
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);
}
}
}
public static <T> void fill(Addable<T> addable,Generator<T> generator,int size){
for(int i = 0;i < size;i++)
addable.add(generator.next());
}
}
//适配器1
class AddableCollectionAdapter<T> implements Addable<T>{
private Collection<T> c;
public AddableCollectionAdapter(Collection<T> c){
this.c = c;
}
@Override
public void add(T t) {
c.add(t);
}
}
//适配器2,使用泛型方法,这是产生更优雅的代码的一种惯用技巧
class Adapter{
public static <T> Addable<T> collectionAdapter(Collection<T> c){
return new AddableCollectionAdapter<T>(c);
}
}
//使用继承来创建这个适配器3
class AddableSimpleQueue<T> extends SimpleQueue<T> implements Addable<T>{
public void add(T item){
super.add(item);
}
}
import java.util.ArrayList;
import java.util.List;
import t4j.generics.coffee.Coffee;
import t4j.generics.coffee.Latte;
import t4j.generics.coffee.Mocha;
public class Fill2Test {
public static void main(String[] args) {
List<Coffee> carrier = new ArrayList<Coffee>();
Fill2.fill(new AddableCollectionAdapter<Coffee>(carrier), Coffee.class, 3);
Fill2.fill(Adapter.collectionAdapter(carrier), Latte.class, 2);
for(Coffee c : carrier)
System.out.println(c);
System.out.println("-----------------------------------------------");
AddableSimpleQueue<Coffee> coffeeQueue = new AddableSimpleQueue<Coffee>();
Fill2.fill(coffeeQueue, Mocha.class, 4);
Fill2.fill(coffeeQueue, Latte.class, 1);
for(Coffee c : coffeeQueue)
System.out.println(c);
}
}
3、讲函数对象用作策略--其实就是策略模式来实现了
/**
*
*/
package t4j.generics;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
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();
}
interface UnaryPredicate<T> {
boolean test(T x);
}
public class Functional {
//循环执行combine()
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;
}
return null;
}
//循环执行function()
public static <T> Collector<T> forEach(Iterable<T> seq,Collector<T> func){
for(T t: seq)
func.function(t);
return func;//返回Collector对象
}
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;
}
//循环执行test(),返回list
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;
}
//策略模式
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);
}
}
//BigInteger的加法
static class BigIntegerAdder implements Combiner<BigInteger>{
public BigInteger combine(BigInteger x, BigInteger y) {
return x.add(y);//返回x+y
}
}
static class AtomicLongAdder implements Combiner<AtomicLong>{
public AtomicLong combine(AtomicLong x, AtomicLong y) {
return new AtomicLong(x.addAndGet(y.get()));
}
}
static class BigDecimalUlp implements UnaryFunction<BigDecimal, BigDecimal>{
public BigDecimal function(BigDecimal x) {
return x.ulp();//返回此 BigDecimal 的 ulp(最后一位的单位)的大小。
}
}
//T的上边界是Comparable,Integer类是实现了Comparable接口的
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;//拿x和bound比较,结果是-1,0,1
}
}
//*
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) {
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)));//从4开始
System.out.println(forEach(li, new MultiplyingIntegerCollector()).result());//*
System.out.println(forEach(filter(li, new GreaterThan<Integer>(4))
, new MultiplyingIntegerCollector()).result());//先获得大于4的数,再*
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))));//大精度的过滤,输出3以上
//从11开始打印11次,下一个素数
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());//把上边的lbi加起来
System.out.println(rbi);
System.out.println(rbi.isProbablePrime(5));
List<AtomicLong> lal = Arrays.asList(new AtomicLong(11),new AtomicLong(47)
,new AtomicLong(74),new AtomicLong(113));
AtomicLong ral = reduce(lal, new AtomicLongAdder());
System.out.println(ral);
System.out.println(transform(lbd, new BigDecimalUlp()));
}
}
这个例子我特意话了下类图,因为类太多,方便整理一下思路
从2、3这两个例子探索了大半天,他们都有一个共同点去对潜在类型机制作出补偿
1、使用泛型的接口:因为接口就是方法的抽象,很接近“我不关心我在这里使用的类型,只要他具有这些方法即可”。然后作出不同的接口实现,无论使用适配器还是策略都是一样。
interface Addable<T> {
void add(T t);
}
2、用一个静态泛型方法来调用不同接口的实现类的方法,这样代码就变得更优雅了。
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);
}
}
}
本人发现2、3例子的共同点就是这些,只是针对不同的场景用了不同的设计模式而已。
就说那么多吧,希望对你了解这个有用,分享并进步着。