JAVA泛型的潜在类型机制

最近在看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例子的共同点就是这些,只是针对不同的场景用了不同的设计模式而已。

就说那么多吧,希望对你了解这个有用,分享并进步着。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值