Java泛型

上一篇博文java8函数式编程--收集器collector:(http://my.oschina.net/joshuashaw/blog/487322)讲得比较随性,并没有把源码一句一句拿出来分析,后来发现groupingBy方法最后有一个if-else分支用来返回不同类型的collector,一个是不需要特定finisher的,另一个需要使用下游收集器的finisher,今天细看源码,发现了几句神奇的代码,拿出来讲一讲。

先贴源码:

    public static <T, K, D, A, M extends Map<K, D>>
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
            downstreamAccumulator.accept(container, t);
        };
        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
        @SuppressWarnings("unchecked")
        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
        }
        else {
            /*---------------------------
            ----    --神奇的代码--   ------
            -----------------------------
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<Map<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            -----------------------------
            -----  ---神奇的代码-----  ----
            --------------------------*/
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
        }
    }

抽出来强调一下

            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
            Function<Map<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };

这里我们看到,类型为

(Function<A, D>) downstream.finisher()

被强制类型转换成

(Function<A, A>) downstreamFinisher

然后是

Map<K,A> intermediate

被强制类型转换成

Map<K,D> intermediate

我想,这都行?于是我写了两条语句

Fuction<String,Integer> f1 = Integer::parse;
Fuction<String,String> f2 = (Fuction<String,String>) f1;

编译器报错。

但是为什么groupingBy方法里面可以这样写?于是我按照groupingBy方法写了一个测试类,代码如下:

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class InterestingTest<K,T,V> {
	private Map<K,T> Tmap = null;
	private Map<K,V> Vmap = null;
	
	private Function<T,V> Vf = null;
	private Function<T,T> Tf = null;
	
	public InterestingTest(Map<K,T> m,Function<T,V> f){
		Tmap = m;
		Vf = f;
		Tf = (Function<T, T>) f;
		
		Tmap.replaceAll((k,t)->Tf.apply(t));
		Vmap = (Map<K, V>) Tmap;
	}
	
	public Map<K, V> getMap(){
		return Vmap;
	}
	
	public static void main(String[] args) {
		Map<String,Integer> map = new HashMap<>();
		map.put("1", 1);
		map.put("2", 2);
		map.put("3", 3);
		map.put("4", 4);
		
		Map<String,String> newMap =
			new InterestingTest<String,Integer,String>(map,Integer::toBinaryString)
				.getMap();
		
		newMap.entrySet().stream()
		.forEach(e->{System.out.println(e.getKey()+" "+e.getValue());});
	}
	
}

代码只是报警告,一运行下来一点问题都没有,完美得出结果。

几天前刷知乎看到java实现不了真正的泛型,现在算是明白了。

其实,对于java泛型的实现,只是编译器在编译阶段帮助你进行类型转型,像Map<String,Integer>类型,实际是保存你的对象的地址,对于Map来说,他只是存了Integer的地址,将Integer视为终极父类Object的子类,当你调用get(key)的时候,最后返回Object类型给你之前帮你强制类型转换成了Integer,就像:

put(key,IntegerObject){
    this.object = IntegerObject;
}

get(key){
    return (Integer) findCorrentObject;
}

所以从泛型的角度看,代码没有错误,但是会警告你这代码可能导致类型转换而出现的错误,于是我们可以看到

@SuppressWarnings("unchecked")

来去除警告。

但是,当你使用的是具体的类型时,编译器有职责给你报错,他认为你写的这行代码很有可能发生错误。



总结:都是兼容和初始开发人员省事而留下的问题啊。

你可能感兴趣的:(Java泛型)