本文介绍了为什么我不能投放Collection< GenericFoo>到Collection< GenericFoo&gt ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题的症结在于,为什么这会导致编译时错误?

The crux of the question is, why does this cause a compile-time error?

List<Collection> raws = new ArrayList<Collection>();
List<Collection<?>> c = raws; // error

背景

我理解为什么泛型通常不会协变.如果我们可以将List<Integer>分配给List<Number>,我们将自己暴露于ClassCastExceptions:

Background

I understand why generics aren't covariant in general. If we could assign List<Integer> to List<Number>, we'd expose ourselves to ClassCastExceptions:

List<Integer> ints = new ArrayList<Integer>();
List<Number> nums = ints; // compile-time error
nums.add(Double.valueOf(1.2));
Integer i = ints.get(0); // ClassCastException

我们在第2行收到一个编译时错误,以使我们从第4行的运行时错误中解脱出来.

We get a compile-time error at line 2 to save us from a run-time error at line 4. That makes sense.

但是这怎么办?

List<Collection> rawLists = new ArrayList<Collection>();
List<Collection<?>> wildLists = rawLists; // compile-time error

// scenario 1: add to raw and get from wild
rawLists.add(new ArrayList<Integer>());
Collection<?> c1 = wildLists.get(0);
Object o1 = c1.iterator().next();

// scenario 2: add to wild and get from raw
wildLists.add(new ArrayList<String>());
Collection c2 = rawLists.get(0);
Object o2 = c2.iterator().next();

在这两种情况下,最终我只获得了Object个元素而没有进行强制转换,因此无法获得神秘的" ClassCastException.

In both scenarios, ultimately I get only get Object elements without casting, so I can't get a "mysterious" ClassCastException.

JLS中与此对应的部分是§4.10.2,因此我理解了为什么编译器会给我错误;我不明白的是为什么这样写规范,以及(为了避免基于投机/基于观点的答案),它是否真的为我提供了编译时的安全性.

The section in the JLS that corresponds to this is §4.10.2, so I understand why the compiler is giving me the error; what I don't get is why the spec was written this way, and (to ward off speculative/opinion-based answers), whether it actually provides me any compile-time safety.

如果您想知道,这里是用例(精简版):

In case you're wondering, here's (a stripped-down version of) the use case:

public Collection<T> readJsons(List<String> jsons, Class<T> clazz) {
    List<T> list = new ArrayList<T>();
    for (String json : jsons) {
        T elem = jsonMapper.readAs(json, clazz);
        list.add(elem);
    }
    return list;
}

// call site
List<GenericFoo<?>> foos = readJsons(GenericFoo.class); // error

错误是因为GenericFoo.class具有类型Class<GenericFoo>,而不是Class<GenericFoo<?>>().我不确定为什么会这样,尽管我怀疑这是一个相关原因.但是无论如何,如果Class<GenericFoo>可以隐式或显式地强制转换为Class<GenericFoo<?>>,那都不是问题.

The error is because GenericFoo.class has type Class<GenericFoo>, not Class<GenericFoo<?>> (§15.8.2). I'm not sure why that is, though I suspect it's a related reason; but regardless, that wouldn't be a problem if Class<GenericFoo> could be casted — either implicitly or explicitly — to Class<GenericFoo<?>>.

推荐答案

首先,原始类型和通配符类型完全不同.首先,原始类型会完全擦除所有通用信息.

First of all, raw type and wildcard type are quite different. For one, raw type completely erases all generic information.

所以我们有List<x>List<y>,其中x不是y.这当然不是子类型关系.

So we have List<x> and List<y> where x is not y. This is certainly not subtype relationship.

尽管如此,您仍然可以要求强制转换.但是请阅读 JLS 5.5.1 ,然后告诉我您要添加更多内容:)浏览整个页面,实际上,这是一长串仅用于投射的文本.

You can, nevertheless, ask the casting to be allowed. But please readJLS 5.5.1 , and tell me you want to add something more to it:) Browse the whole page, actually, it's a great wall of text just for casting.

请记住,这只是整个效果中的第一个涟漪. List<List<x>>List<List<y>>等如何

And remember this is just the first ripple in the whole effect. What about List<List<x>> and List<List<y>>, etc.

这篇关于为什么我不能投放Collection&lt; GenericFoo&gt;到Collection&lt; GenericFoo&gt ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 15:50