为什么下面这行代码在 HashMap 中会报错?它没有在作业的右侧使用通配符。
Map<String,?> map=new HashMap<String,?>();
您不能像这样实例化参数化类型。通配符参数化类型不是具体类型,因此它们不能出现在新表达式中。
通配符参数化类型表示包含泛型类型的具体实例的类型族。所使用的通配符的种类决定了哪些具体的参数化类型属于该族。
所以,Map<String,?>
表示类型族,可以是Map<String, Object>
, Map<String, String>
, 任何东西。您必须在创建实际地图时使用具体类型。
所以,你可以这样做:
Map<String,?> map=new HashMap<String, String>();
Map<String,?> map=new HashMap<String, Object>();
但是这个声明的问题是,你不能向 map 添加任何东西,除了null
.
另一方面,考虑其他类型的通配符——上限和下限。
Map<String, ? extends Number>
此类型表示的类型族是具体实例化,其中值类型是Number
或 的子类型Number
。因此,对于这个,以下是具体参数化类型的有效创建:
Map<String, ? extends Number> map = new HashMap<String, Number>();
Map<String, ? extends Number> map = new HashMap<String, Integer>();
但同样,这里的问题是你不能在地图中添加任何东西,除了null
之前从中获取的值。
Map<String, ? super Integer>
如您所知,您不能使用无界通配符或上限通配符向通配符参数化类型添加任何内容。还有第三种类型 - 下界通配符,如果您要向地图添加内容,可以使用它。上述参数化类型的类型族是接受类型值Integer
或其超类型的类型。因此,您可以像这样实例化它:
Map<String, ? super Integer> map = new HashMap<String, Number>();
Map<String, ? super Integer> map = new HashMap<String, Integer>();
Map<String, ? super Integer> map = new HashMap<String, Serializable>();
但这里还有另一个问题。虽然你可以给它添加一个值,但是当你获取一些值时,你不能确定你得到的是什么类型。
因此,根据您的要求,您可能必须使用一种或另一种类型的通配符。问题中的更多信息可能会对您有所帮助。但是,一般请记住,您不能创建通配符参数化类型的对象,而只能创建具体的参数化类型。
做就是了:
class SuperBogusUnrelatedClass {}
// ...
Map<String, ?> map = new HashMap<String, SuperBogusUnrelatedClass>();
以上是正确的,并且 100% 类型安全。说真的,你可以把任何东西放在那里,甚至Math
。为什么是正确的?由于它是通配符,这意味着它可以是任何东西;你不知道它是什么。
上面例子的荒谬也说明了为什么这个初始化几乎完全没用——因为类型参数是未知的,你不能安全地将任何值(除了null
)放入Map<String, ?>
. 因此,您Map
要么必须为空,要么必须填充值为null
. 所以基本上,它相当于一个Set
.
实例化具体类的对象时不能使用通配符。
由于您正在创建一个HashMap
对象,因此您必须指定所有通用参数。
在 Java 7 及更高版本中,您可以只使用此处提到的菱形符号:
https://docs.oracle.com/javase/tutorial/java/generics/types.html#diamond
这是使用从问题中显示的代码行派生的菱形的快速示例:
Map<String,?> map=new HashMap<>();
您正在实例化一个类型为类型参数的对象。这是不可能的。
因为编译器不知道如何创建未知类型的对象。
更多详细信息我可以创建一个类型为类型参数的对象吗?