为什么以下代码行在HashMap中出错?它并没有在任务的右侧使用外卡。
Map<String,?> map=new HashMap<String,?>();
答案 0 :(得分:14)
您不能像这样实例化参数化类型。通配符参数化类型不是具体类型,因此它们不能出现在新表达式中。
通配符参数化类型表示包含泛型类型的具体实例的类型族。正在使用的通配符类型决定了哪些具体参数化类型属于该族。
因此,Map<String,?>
表示类型系列,可以是Map<String, Object>
,Map<String, String>
,任何内容。您必须在创建实际地图时使用具体类型。
所以,你可以这样做:
Map<String,?> map=new HashMap<String, String>();
Map<String,?> map=new HashMap<String, Object>();
但是这个声明的问题在于,除了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>();
但这里还有另一个问题。虽然你可以为它添加一个值,但是当你获取一些值时,你无法确定你得到的是什么类型。
因此,根据您的要求,您可能必须使用一种或另一种类型的通配符。可能是问题中的更多信息可能对您有所帮助。但是,一般只记得,你不能创建一个通配符参数化类型的对象,而只能创建具体的参数化类型。
答案 1 :(得分:2)
在实例化具体类的对象时,不能使用通配符。
答案 2 :(得分:2)
只是做:
class SuperBogusUnrelatedClass {}
// ...
Map<String, ?> map = new HashMap<String, SuperBogusUnrelatedClass>();
以上是正确的,100%类型安全。说真的,你可以放任何东西,甚至Math
。为什么这是正确的?因为它是一个通配符,它意味着它可以是任何东西;你不知道它是什么。
上面例子的荒谬也说明了为什么这个初始化几乎完全没用 - 因为type参数是未知的,你不能安全地将任何值(null
除外)放入{{1} }。因此,您的Map<String, ?>
必须为空,或者填充值为Map
的条目。所以基本上,它等同于null
。
答案 3 :(得分:1)
由于您要创建HashMap
对象,因此必须指定所有通用参数。
答案 4 :(得分:1)
在Java 7及更高版本中,你可以使用这里提到的钻石符号:
https://docs.oracle.com/javase/tutorial/java/generics/types.html#diamond
以下是使用从问题中显示的代码行派生的钻石的快速示例:
public class ClassUser
{
....
public virtual ICollection<ClassGroup> Groups { get; set; }
}
public class ClassPermission
{
....
public virtual ICollection<ClassGroup> Groups { get; set; }
}
public class ClassGroup
{
....
public virtual ICollection<ClassUser> Users { get; set; }
public virtual ICollection<ClassPermission> Permissions { get; set;
}
答案 5 :(得分:0)
您正在实例化一个类型为类型参数的对象。这是不可能的
因为编译器不知道如何创建未知类型的对象。
更多详情Can I create an object whose type is a type parameter?