简而言之:您cannot使用getOrDefault
、at all,任何"V"被声明为?
或? extends Anything
的 map .克隆JDK源代码或使用自己的take on getOrDefault
创建实用方法都无法解决这一问题.
可以想象,getOrDefault
实现不会有这个问题.不幸的是,OpenJDK源代码没有正确编写,或者我没有看到一些折衷.不幸的是,"修复它"是向后不兼容的,所以它可能永远不会发生;我们被损坏的getOrDefault卡住了.谢谢你提出这个问题——通过思考,我意识到它坏了.我现在感到很遗憾,在被问及反馈时,我没有对amber dev给出反馈:)
对为什么要这样做的解释有点详细,需要良好的直觉和泛型如何工作的知识.如果你感兴趣,戴上你的思考帽,继续读下go !
那么,为什么?
Map<Integer, ? extends Collection<Integer>> map
好的:这意味着这个map
变量可以指向,例如,new HashMap<Integer, List<Integer>>()
.或者,它可以指向new HashMap<Integer, Set<Integer>>()
甚至new HashMap<Integer, Collection<Integer>>()
.
map.getOrDefault(....)
哦哦.这是不可能的.您需要提供一个默认值,此默认值必须"起作用"regardless of what the map is actually pointing at-它需要与此映射中的值的类型相同.想象一下,你有一个Map<Integer, Set<Integer>>
-什么可行?好吧,new HashSet<Integer>()
行.但是对于all 3(Set<Integer>
、List<Integer>
和Collection<Integer>
,当然还有任何其他集合类型,它们的数量是无限的),什么才有效呢?
答案是nothing.
你不能这样做.在这里,你根本不能用getOrDefault
.好吧,除非你简单地通过null
,字面上来说,这是唯一的"所有类型"的值,但是你应该只写.get(k)
,而不是.getOrDefault(k, null)
.
固定版本
这是直接从OpenJDK源代码粘贴的getOrDefault
的实现:
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
从根本上说,这永远不会对你有用-如果V是? anything
,你就不会有V-那?意思是:我们知道类型是什么,也没有表示它的typevar,所以没有表达式可以匹配.在这里,对getOrDefault的这种理解可以很好地发挥作用:
default <Z super V> getOrDefault(Object key, Z defaultValue) {
Z z;
return (((z = get(key) != null) || containsKey(key))
? z
: defaultValue;
}
这里发生的事情是,在这种情况下,虽然映射可能是一个集合或列表等,但您只希望它是Collection<Integer>
,实际上您并不"在意",如果默认值不是"V",您就可以了(如果您的映射实际上是Map<Integer, List<Integer>>
,您不介意调用getOrDefault是否最终会给您一个不是List<Integer>
-Collections.empty()
的对象).
因此,我们需要确定存在一些新的类型Z,它是V的超类型(从而保证如果映射中的键is,您会得到一个V,这绝对是一种Z,根据声明,Z是V的超类型),并且有一个默认值,它也绝对是Z类型,从而保证在任何一个"分支"(找到键,但找不到键)中,返回的值至少为Z.
但是,map并不是这样工作的,因此您根本不能使用.getOrDefault
.
我不认为此时修改getOrDefault
是向后兼容的,所以我认为向openjdk核心团队提交特性请求没有任何意义:他们只会拒绝它,我们坚持使用编写的getOrDefault.但是,如果必须使用静态实用程序方法来执行上述操作,则可以创建静态实用程序方法.请注意,您可能希望以不同的方式编写它—强制转换为原始,在原始模式下执行工作,忽略警告,然后进行清理.理论上,一些Map实现可能会有不同的getOrDefault实现,尽管我很难想象它会是什么样子(比如说,computeIfAbsent
绝对有重要的自定义实现,例如在ConcurrentHashMap中).