简体   繁体   English

Java泛型和集合

[英]Java Generics and Collections

I have a question about Java Generics and Collections. 我有一个关于Java Generics和Collections的问题。 It's considered good practice to declare a collection like this: 声明像这样的集合被认为是一种好习惯:

List<String> catNames = new ArrayList<String>();

because you can change the type of the List and not worry about breaking the rest of your code. 因为您可以更改List的类型,而不必担心会破坏其余的代码。 But when I try to do this: 但是当我尝试这样做时:

private static Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, ArrayList<Issue>>();

javac complains javac抱怨

Type mismatch: cannot convert from HashMap<ResultsAggregator.IssueType,ArrayList<Issue>> to HashMap<ResultsAggregator.IssueType,List<Issue>>

Moreover, this is perfectly legal: 而且,这是完全合法的:

private static Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, List<Issue>>();

which seems even more confusing, because List is an interface, not a concrete class. 这似乎更令人困惑,因为List是一个接口,而不是具体的类。 What's going on here? 这里发生了什么? Is this a type erasure issue? 这是一种类型擦除问题吗?

If it was legal to compile such a code, you would've been able to sneakily insert element of other types in the HashMap : 如果编译这样的代码是合法的,你就可以偷偷地在HashMap插入其他类型的元素:

HashMap<IssueType, List<Issue>> a = new HashMap<IssueType, ArrayList<Issue>>();
a.put(someIssue, new SomeClassThatImplementsListOfIssueButIsNotArrayList());

which is not what you expect. 这不是你所期望的。 ArrayList<String> is a List<String> , but that's not enough for this code to be safe and correct. ArrayList<String>是一个List<String> ,但这还不足以使此代码安全无误。 To be safe, it also requires List<String> to be ArrayList<String> , which means the generic type argument is not covariant here. 为了安全起见,它还要求List<String>ArrayList<String> ,这意味着泛型类型参数在此处不是协变的。

Your last code is legal because nothing requires the type parameter to be a concrete class. 您的上一个代码是合法的,因为没有必要将type参数作为具体类。 Similarly, nothing requires a field to be of an abstract type. 同样,没有什么要求字段是抽象类型。

There is not reason to specify an ArrayList in your second example. 在第二个示例中没有理由指定ArrayList。 It doesn't actually create a list so it is best to put the interface in there anyway. 它实际上并不创建列表,因此最好将接口放在那里。 You will later then able able to call the following just fine. 您稍后可以调用以下内容。

Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, List<Issue>>();

orphanedAttrMap.put(IssueType.TYPE, new ArrayList<Issue>());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM