Java通用问题

pat*_*rit 3 java generics inheritance types

下面的代码编译,但如果我取消注释注释行,它不会,我很困惑为什么.HashMap确实扩展了AbstractMap,并且声明map的第一行编译正常.

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String args[]) {
        Map<String, ? extends AbstractMap<String, String>> map = new HashMap<String, HashMap<String, String>>();
        //map.put("one", new HashMap<String, String>());
    }
}
Run Code Online (Sandbox Code Playgroud)

而且,我知道"正确的方法"是这样的:

import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String args[]) {
        Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
        map.put("one", new HashMap<String, String>());
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 7

第一个代码是不安全的 - 假设你真的写了:

HashMap<String, ConcurrentHashMap<String, String>> strongMap = 
    new HashMap<String, ConcurrentHashMap<String, String>>();
Map<String, ? extends AbstractMap<String, String>> map = strongMap;
Run Code Online (Sandbox Code Playgroud)

现在:

map.put("one", new HashMap<String, String>());
ConcurrentHashMap<String, String> x = strongMap.get("one");
Run Code Online (Sandbox Code Playgroud)

我们应该ConcurrentHashMap- 但实际上我们只有一个HashMap.

如果我们减少正在进行的泛型数量,这实际上要简单得多解释......你的场景实际上相当于(比如说):

List<? extends Fruit> list = new List<Apple>();
list.add(new Apple());
Run Code Online (Sandbox Code Playgroud)

看起来没问题,直到你认为它的有效性(就编译器而言)相当于:

List<Apple> apples = new ArrayList<Apple>();
List<? extends Fruit> list = apples;
list.add(new Orange());
Apple apple = list.get(0); // Should be okay... but element 0 is an Orange!
Run Code Online (Sandbox Code Playgroud)

这显然是正常.编译器必须以相同的方式处理这两个,因此它们都使它们无效.

  • @ user450602:当你*不需要时.例如,如果你传递一个`List <?将Fruit>`扩展为一个方法,它可以*得到*任何值,并且知道它是一个`Fruit`,这可能就是它所需要的.如果你传入一个`List <?超级水果>`然后它知道它可以*添加*任何水果,但不知道它可以从列表中获得什么类型. (2认同)