Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 不同的治疗方法?在扩展和超级_Java_Generics - Fatal编程技术网

Java 不同的治疗方法?在扩展和超级

Java 不同的治疗方法?在扩展和超级,java,generics,Java,Generics,我希望可以使用任何类型来代替通配符(?) extends也是如此(正如我所预料的),但super是一个编译错误(我不明白为什么它与extends示例不同) 我该如何看待这种差异——这是一个bug还是一个特性 class Why { void fSuper(List<? super Map<String,?>> lst) { } void fExtends(List<? extends Map<String,?>>

我希望可以使用任何类型来代替通配符(?)

extends也是如此(正如我所预料的),但super是一个编译错误(我不明白为什么它与extends示例不同)

我该如何看待这种差异——这是一个bug还是一个特性

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>  >