为什么java.util.Properties实现Map <Object,Object>而不是Map <String,String>

java.util.Properties类是为了表示键和值都是string的映射。 这是因为Properties对象用于读取文本文件.properties文件。

那么,为什么在Java 5中他们改造了这个类来实现Map<Object,Object>而不是Map<String,String>呢?

javadoc说:

由于Properties从Hashtableinheritance,put和putAll方法可以应用于Properties对象。 强烈build议不要使用它们,因为它们允许调用者插入其键或值不是string的条目。 应该使用setProperty方法。 如果store或save方法在包含非String键或值的“受损”Properties对象上调用,则调用将失败。

由于键和值都被认为是string,那么为什么不使用适当的generics来强制执行?

我猜使Properties实现Map<String,String>不能完全向后兼容为Java 5以前版本编写的代码。如果你有老的代码将非string粘贴到一个Properties对象中,那么这个代码将不再使用Java 5进行编译但是…不是件好事吗? generics的全部不是在编译时捕获这种types的错误吗?

因为他们在Java早期做得很快,并没有意识到后来的版本会有什么变化。

generics被认为是从一开始就是Javadevise的一部分,但是这个特性被放弃了,因为它太复杂了,在当时是不必要的。 因此,标准库中的很多代码都是在假设非generics集合的情况下编写的。 马丁·奥德斯基(Martin Odersky)用原型语言“比萨”(Pizza)来展示它们如何在保持接近完美的向后兼容性的同时,以Java代码和字节码的方式完成。 这个原型导致了Java 5,其中集合类被改进为generics,允许旧代码继续工作。

不幸的是,如果他们追溯地从Map<String, String>inheritance了Properties ,那么以下先前有效的代码将停止工作:

 Map<Object, Object> x = new Properties() x.put("flag", true) 

为什么有人会这么做呢,但是Sun对Java向后兼容的承诺已经超越了英雄般的意义。

现在大部分受过教育的观察者所赞赏的是, Properties决不应该从Mapinheritance。 它应该围绕着Map ,只展示那些有意义的Map的特性。

马丁·奥德斯基(Martin Odersky)自从重塑Java以来​​,一直致力于开发更新颖的Scala语言,inheritance更less的错误,在一些领域开创了新的天地。 如果你发现Java的烦人的烦恼,请看看它。

最初的意图是, Properties确实会扩展Hashtable<String,String> 。 不幸的是桥接方法的实现引起了一个问题。 以这种方式定义的Properties会导致javac生成合成方法。 Properties应该定义一个返回Stringget方法,但是需要重写一个返回Object的方法。 所以join了一种合成桥梁的方法。

假设你有一个在老的1.4天里写的课。 你已经覆盖了Properties一些方法。 但是你没有做的是重写新的方法。 这导致意想不到的行为。 为了避免这些桥接方法, Properties扩展了Hashtable<Object,Object> 。 同样, Iterable不会返回(只读) SimpleIterable ,因为这会将方法添加到Collection实现中。

用于创build来自属性的Map的单线(不带警告的双线):

 @SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, String> sysProps = new HashMap(System.getProperties()); 

向后兼容。

原因: Liskov替代原则和向后兼容。 Properties扩展了Hashtable ,因此必须接受Hashtable可以接受的所有消息 – 这意味着接受put(Object, Object) 。 而且它必须扩展纯Hashtable而不是Hashtable<String, String>因为generics是通过types擦除以向下兼容的方式实现的,所以一旦编译器做了它的事情,就没有generics。