为什么 java.util.Properties 实现 Map<Object,Object> 而不是 Map<String,String>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/873510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does java.util.Properties implement Map<Object,Object> and not Map<String,String>
提问by Mike Kucera
The java.util.Propertiesclass is meant to represent a map where the keys and values are both Strings. This is because Propertiesobjects are used to read .propertiesfiles, which are text files.
的java.util.Properties类是代表一地图,其中键和值都是字符串。这是因为Properties对象用于读取.properties文件,这些文件是文本文件。
So, why in Java 5 did they retrofit this class to implement Map<Object,Object>and not Map<String,String>?
那么,为什么在 Java 5 中他们改造了这个类来实现Map<Object,Object>而不是Map<String,String>?
The javadocstates:
该javadoc的状态:
Because Properties inherits from Hashtable, the put and putAll methods can be applied to a Properties object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are not Strings. The setProperty method should be used instead. If the store or save method is called on a "compromised" Properties object that contains a non-String key or value, the call will fail.
因为 Properties 继承自 Hashtable,所以 put 和 putAll 方法可以应用于 Properties 对象。强烈建议不要使用它们,因为它们允许调用者插入键或值不是字符串的条目。应改用 setProperty 方法。如果在包含非字符串键或值的“受损”属性对象上调用 store 或 save 方法,则调用将失败。
Since the keys and values are both supposed to be Strings then why not enforce that statically by using the proper generic type?
既然键和值都应该是字符串,那么为什么不通过使用适当的泛型类型静态地强制执行呢?
I guess making Propertiesimplement Map<String,String>would not be fully backward compatible with code written for pre-Java 5. If you have older code that sticks non-strings into a Properties object then that code would no longer compile with Java 5. But... isn't that a good thing? Isn't the whole point of generics to catch such type errors at compile time?
我猜制作Properties工具Map<String,String>不会与为前 Java 5 编写的代码完全向后兼容。如果您有将非字符串粘贴到 Properties 对象中的旧代码,那么该代码将不再使用 Java 5 进行编译。但是......不是'那是件好事吗?泛型的全部意义不是在编译时捕获此类类型错误吗?
回答by Marcus Downing
Because they did it in a hurry in the early days of Java, and didn't realise what the implications would be four versions later.
因为他们在Java的早期就匆匆忙忙地做了,并没有意识到四个版本之后的含义。
Generics were supposed to be part of the design of Java from the beginning, but the feature was dropped as being too complicated and, at the time, unnecessary. As a result, lots of code in the standard libraries is written with the assumption of non-generic collections. It took the prototype language "Pizza" from Martin Odersky to show how they could be done fairly well while maintaining near perfect backwards compatibility, with both Java code and bytecode. The prototype led to Java 5, in which the collections classes were retrofitted with generics in a way that allowed old code to keep working.
泛型从一开始就应该是 Java 设计的一部分,但由于太复杂而且在当时没有必要,因此放弃了该功能。因此,标准库中的许多代码都是在假设非泛型集合的情况下编写的。它采用了 Martin Odersky 的原型语言“Pizza”来展示如何在保持近乎完美的向后兼容性的同时,对 Java 代码和字节码进行很好的处理。原型导致了 Java 5,其中集合类被改造为泛型,允许旧代码继续工作。
Unfortunately, if they were to retroactively make Propertiesinherit from Map<String, String>, then the following previously valid code would stop working:
不幸的是,如果他们追溯使Properties继承自Map<String, String>,那么以下以前有效的代码将停止工作:
Map<Object, Object> x = new Properties()
x.put("flag", true)
Why anybody would do that is beyond me, but Sun's commitment to backwards compatibility in Java has gone beyond heroic into the pointless.
我无法理解为什么有人会这样做,但 Sun 对 Java 向后兼容性的承诺已经超越了英雄主义,变得毫无意义。
What's now appreciated by most educated observers is that Propertiesshould never have inherited from Mapat all. It should instead wrap around Map, exposing only those features of Map that make sense.
大多数受过教育的观察家现在赞赏的是,它们Properties根本不应该继承Map。相反Map,它应该环绕,只暴露 Map 的那些有意义的特性。
Since reinventing Java, Martin Odersky has gone on to create the new Scala language, which is cleaner, inherits fewer mistakes, and breaks new ground in a number of areas. If you're finding Java's niggles annoying, take a look at it.
自从重新发明 Java 以来,Martin Odersky 继续创建了新的 Scala 语言,它更简洁,继承的错误更少,并在许多领域开辟了新天地。如果您发现 Java 的小问题很烦人,请看一看。
回答by Tom Hawtin - tackline
It was originally intended that Propertieswould indeed extends Hashtable<String,String>. Unfortunately the implementation of bridge methods caused a problem. Propertiesdefined in such a way causes javac to generate synthetic methods. Propertiesshould define, say, a getmethod that returns a Stringbut needs to override a method that returns Object. So a synthetic bridge method is added.
它原本打算Properties确实扩展Hashtable<String,String>. 不幸的是,桥接方法的实现引起了一个问题。Properties以这种方式定义会导致 javac 生成合成方法。Properties应该定义,比如说,一个get返回 a的方法,String但需要覆盖一个返回Object. 所以增加了合成桥法。
Suppose you had a class written in the bad old 1.4 days. You've overridden some methods in Properties. But what you haven't done is overridden the new methods. This leads to unintended behaviour. To avoid these bridge methods, Propertiesextends Hashtable<Object,Object>. Similarly Iterabledoes not return a (read-only) SimpleIterable, because that would have added methods to Collectionimplementations.
假设你有一门课是在过去的 1.4 天里写的。您已经覆盖了Properties. 但是你还没有做的是覆盖新方法。这会导致意外行为。为了避免这些桥接方法,Properties扩展Hashtable<Object,Object>. 同样Iterable不返回 a (read-only) SimpleIterable,因为这会向Collection实现添加方法。
回答by Spajus
A one-liner (two-liner for no warnings) for creating Map from Properties:
用于从属性创建地图的单行(没有警告的两行):
@SuppressWarnings({ "unchecked", "rawtypes" })
Map<String, String> sysProps = new HashMap(System.getProperties());
回答by KitsuneYMG
Backwards compatibility.
向后兼容性。
回答by Michael Borgwardt
The reason: Liskov substitution principleand backwards compatibility. Propertiesextends Hashtableand thus must accept all messages that Hashtablewould accept - and that means accepting put(Object, Object). And it has to extend plain Hashtableinstead of Hashtable<String, String>because Generics were implemented in the downwards-compatibe way via type erasure, so once the compiler has done its thing, there are no generics.
原因:Liskov 替换原则和向后兼容性。PropertiesextendsHashtable并且因此必须接受所有Hashtable可以接受的消息——这意味着接受put(Object, Object). 它必须扩展Hashtable而不是Hashtable<String, String>因为泛型是通过类型擦除以向下兼容的方式实现的,所以一旦编译器完成了它的工作,就没有泛型。

