java.util.Properties
类用于表示键和值都是字符串的映射。这是因为Properties
个对象用于读取.properties
文件,这些文件是文本文件。
那么,为什么在Java 5中他们改进了这个类以实现Map<Object,Object>
而不是Map<String,String>
?
javadoc州:
因为Properties继承自Hashtable,所以put和putAll方法可以应用于Properties对象。强烈建议不要使用它们,因为它们允许调用者插入其键或值不是字符串的条目。应该使用setProperty方法。如果在包含非String键或值的“受损”Properties对象上调用store或save方法,则调用将失败。
由于键和值都应该是字符串,那么为什么不使用正确的泛型类型静态强制执行呢?
我认为使Properties
实现Map<String,String>
不能与为Java 5之前编写的代码完全向后兼容。如果你有旧的代码将非字符串粘贴到Properties对象中,那么该代码将不再用Java 5编译。但是......这不是一件好事吗?在编译时捕获这种类型错误不是泛型的全部意义吗?
答案 0 :(得分:53)
因为他们在Java早期就匆匆忙忙做了这件事,并且没有意识到后来四个版本会带来什么影响。
泛型应该从一开始就是Java设计的一部分,但是由于过于复杂而且当时没有必要,因此该功能被删除了。因此,标准库中的大量代码是在非泛型集合的假设下编写的。它采用了Martin Odersky的原型语言“Pizza”,展示了如何在保持近乎完美的向后兼容性的同时,使用Java代码和字节码完成它们。原型开发了Java 5,其中的集合类使用泛型进行了改进,允许旧代码继续工作。
不幸的是,如果他们追溯Properties
继承Map<String, String>
,则以下有效代码将停止工作:
Map<Object, Object> x = new Properties()
x.put("flag", true)
为什么有人会这样做是超出我的,但是Sun对Java的向后兼容性的承诺已经超越了英雄,变成了毫无意义。
大多数受过教育的观察者现在都认为,Properties
永远不应该从Map
继承。它应该环绕Map
,只暴露那些有意义的Map特征。
自从重新发明Java以来,Martin Odersky已经开始创建新的Scala语言,它更清晰,继承更少的错误,并在许多领域开辟了新天地。如果你发现Java的烦恼很烦人,那就去看看吧。
答案 1 :(得分:27)
最初的意图是Properties
确实会扩展Hashtable<String,String>
。不幸的是,桥接方法的实现引起了一个问题。以这种方式定义的Properties
会导致javac生成合成方法。 Properties
应该定义一个get
方法,该方法返回String
但需要覆盖返回Object
的方法。因此增加了合成桥接方法。
假设你有一个写在糟糕的旧1.4天的课程。你已经覆盖了Properties
中的一些方法。但是你没有做的是覆盖了新的方法。这会导致意外行为。为了避免这些桥接方法,Properties
扩展了Hashtable<Object,Object>
。同样地,Iterable
不返回(只读)SimpleIterable
,因为这会为Collection
实现添加方法。
答案 2 :(得分:13)
用于从属性创建Map的单行(双线无警告):
@SuppressWarnings({ "unchecked", "rawtypes" })
Map<String, String> sysProps = new HashMap(System.getProperties());
答案 3 :(得分:4)
向后兼容性。
答案 4 :(得分:2)
原因:Liskov substitution principle和向后兼容性。 Properties
扩展Hashtable
,因此必须接受Hashtable
可接受的所有邮件 - 这意味着接受put(Object, Object)
。并且它必须扩展普通Hashtable
而不是Hashtable<String, String>
,因为泛型是通过type erasure以向下兼容的方式实现的,所以一旦编译器完成了它的事情,就没有泛型。 / p>