Java 不同的治疗方法?在扩展和超级
我希望可以使用任何类型来代替通配符(?) extends也是如此(正如我所预料的),但super是一个编译错误(我不明白为什么它与extends示例不同) 我该如何看待这种差异——这是一个bug还是一个特性Java 不同的治疗方法?在扩展和超级,java,generics,Java,Generics,我希望可以使用任何类型来代替通配符(?) extends也是如此(正如我所预料的),但super是一个编译错误(我不明白为什么它与extends示例不同) 我该如何看待这种差异——这是一个bug还是一个特性 class Why { void fSuper(List<? super Map<String,?>> lst) { } void fExtends(List<? extends Map<String,?>>
class Why {
void fSuper(List<? super Map<String,?>> lst) { }
void fExtends(List<? extends Map<String,?>> lst) { }
void test(){
// Why any type instead of ? gives error
fSuper(new ArrayList<Map<String, String>>()); // compile ERR - WHY ???
fSuper(new ArrayList<Map<String, Byte>>()); // c. ERR - WHY ???
fSuper(new ArrayList<Map<String, Map<Short, Boolean>>>()); // c. ERR - WHY ???
fSuper(new ArrayList<Map<String,?>>()); // OK
// Any type instead of ? can be used OK
fExtends(new ArrayList<Map<String, String>>()); // OK
fExtends(new ArrayList<Map<String, Byte>>()); // OK
fExtends(new ArrayList<Map<String, Map<Short, Boolean>>>()); // OK
fExtends(new ArrayList<Map<String,?>>()); // OK
class为什么{
void fSuper(List>lst){}
void fExtends(List>lst){}
无效测试(){
//为什么是任何类型而不是?给出错误
fSuper(newarraylist());//编译错误-为什么???
fSuper(newarraylist());//c.ERR-为什么???
fSuper(newarraylist());//c.ERR-为什么???
fSuper(newarraylist());//确定
//可以使用任何类型而不是?确定
fextens(newarraylist());//确定
fextens(newarraylist());//确定
fextens(newarraylist());//确定
fextens(newarraylist());//确定
这个问题的灵感来源于pdem答案中的示例
他的例子似乎与我的观点很不一致
void populateList(List<? super Map<String,?>> list) {
list.clear();
Map<String, String> map;
map = new HashMap<String,String>();
map.put("key", "value"); // compiles
// Map<String, String> for List<? super Map<String,?>>
list.add(map); // compiles !!
}
void populateList(列表>列表){
list.clear();
地图;
map=新的HashMap();
map.put(“key”、“value”);//编译
//列表的地图>
list.add(map);//编译!!
}
p.S.我理解PEC(Producer extends/Consumer super)。(请不要因为这个原因关闭问题)。但我不知道如何在我的第一个代码段中使用它。我想我完全理解第二个代码段。但我不明白为什么ArrayList
没有在我的第一个代码段中编译(使用…?super)在第二个代码段中编译,在我的第一个代码段中编译(使用…?扩展)
我还意识到使用通配符(?)通常是一种麻烦的方式(特别是在违反PECS规定的情况下)
但是我想深入理解泛型,到目前为止,第一个代码片段超出了我的理解。基于@Nathan Hughes建议的帖子,我发现 具有下界的通配符实例化是泛型类型的所有实例化的超类型,其中类型参数是下界的超类型 在当前情况下,对于
列表>
,我们只能分配类型参数为映射的超级类型的类型
通常,对于下界通配符,我们应该能够以相反的方向分配类型参数(即,在语句中,LHS中的类型参数必须可以分配给RHS中的类型参数)
在下面的代码中,我们无法将前3个值分配给类型参数。因此,具有此类型参数的子类型也无法分配给列表
HashMap m = new HashMap();
Map<String, String> m1 = (Map<String, ?>)(m); //error
Map<String, Byte> m2 = (Map<String, ?>)(m); //error
Map<String, Map<Short, Boolean>> m3 = (Map<String, ?>)(m); //error
Map<String, ?> m4 = (Map<String, ?>)(m); // ok
HashMap m=newhashmap();
映射m1=(映射)(m);//错误
Map m2=(Map)(m);//错误
映射m3=(映射)(m);//错误
映射m4=(映射)(m);//确定
这并不容易,也不短;但本质上并没有那么复杂
你首先需要了解的是泛型是不变的,你可以阅读更多或更长的内容,以及我最近的回答。简单地说:
Animal a = ...
Dog d = ...
a = d;
分配a=d
有效,因为Dog
是Animal
;但同时:
List<Animal> a = new ArrayList<>();
List<Dog> d = new ArrayList<>();
a = d;
将起作用(与上面的示例相反a=d
)
如果我们想要一份狗的名单呢?天真的方法是尝试这样的东西:
List<List<Dog>> dogs = new ArrayList<>();
List<List<Animal>> animals = new ArrayList<>();
animals = dogs;
仍然没有。要使类型可分配,您需要:
List<? extends List<? extends Animal>> animals = new ArrayList<>();
animals = dogs; // now it works
fSuper
的例子在某种程度上更为复杂,但实际上并没有那么复杂。让我们首先看看它需要的论点:List>
:一个未知类型的列表X
,其中X
必须是Map
的超类型(或自类型)。这就是为什么:
fSuper(new ArrayList<Map<String, ?>>());
不编译,因为您需要传递Map
的超类型,是这种情况吗?让我们举例说明:
method-argument: Map < String, ? >
passed-value : Map < String, Map<Short, Boolean> >
方法参数:映射
传递值:Map
Map
是的超类型吗?
不是,它是子类型,因此失败
在同一过程中:
Byte
是的超类型吗?
String
是的超类型吗?
这就是为什么这些方法也会失败。是Map
的超类型还是Map
的子类型?它不能同时是超类型和类型t的子类型。唯一同时是超类型和类型t的子类型是t本身。每一个其他类型都是一个或另一个(或两者都不是).你在这里读过吗?这回答了你的问题吗?我建议你读一下这些答案对你有帮助吗?甚至
List<? extends List<?>> animals = new ArrayList<>();
Map<String,?> one = new HashMap<>();
Map<String, String> two = new HashMap<>();
Map<String, Byte> three = new HashMap<>();
// ... and so on for all the cases you have
one = two;
one = three;
fSuper(new ArrayList<Map<String, ?>>());
fSuper(new ArrayList<Map<String, Map<Short, Boolean>>>())
method-argument: Map < String, ? >
passed-value : Map < String, Map<Short, Boolean> >