The java.util.Properties
class is meant to represent a map where the keys and values are both Strings. This is because Properties
objects are used to read .properties
files, which are text files.
java.util。属性类表示一个映射,其中键和值都是字符串。这是因为属性对象用于读取. 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>
The javadoc states:
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.
因为属性继承自Hashtable,所以put和putAll方法可以应用于属性对象。强烈建议不要使用它们,因为它们允许调用者插入键或值不是字符串的条目。应该使用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 Properties
implement 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?
我认为使属性实现Map
5 个解决方案
#1
52
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 Properties
inherit from Map<String, String>
, then the following previously valid code would stop working:
不幸的是,如果他们要追溯使属性继承自Map
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 Properties
should never have inherited from Map
at all. It should instead wrap around Map
, exposing only those features of Map that make sense.
现在,受教育程度最高的观察家们所欣赏的是,财产不应该从地图上继承下来。相反,它应该围绕着地图,只暴露那些有意义的地图特征。
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的琐碎让人讨厌,看看它。
#2
27
It was originally intended that Properties
would indeed extends Hashtable<String,String>
. Unfortunately the implementation of bridge methods caused a problem. Properties
defined in such a way causes javac to generate synthetic methods. Properties
should define, say, a get
method that returns a String
but needs to override a method that returns Object
. So a synthetic bridge method is added.
属性最初的目的是扩展Hashtable
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, Properties
extends Hashtable<Object,Object>
. Similarly Iterable
does not return a (read-only) SimpleIterable
, because that would have added methods to Collection
implementations.
假设你有一个课程是在糟糕的1.4天里写的。您已经在属性中重写了一些方法。但是您没有做的是重写新方法。这会导致无意识的行为。为了避免这些桥接方法,属性扩展了Hashtable ,object>
#3
13
A one-liner (two-liner for no warnings) for creating Map from Properties:
从属性创建映射的一行程序(无警告的两行程序):
@SuppressWarnings({ "unchecked", "rawtypes" })
Map<String, String> sysProps = new HashMap(System.getProperties());
#4
4
Backwards compatibility.
向后兼容性。
#5
2
The reason: Liskov substitution principle and backwards compatibility. Properties
extends Hashtable
and thus must accept all messages that Hashtable
would accept - and that means accepting put(Object, Object)
. And it has to extend plain Hashtable
instead 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替换原理和向后兼容性。属性扩展了Hashtable,因此必须接受Hashtable将接受的所有消息——这意味着接受put(Object, Object)。它必须扩展普通哈希表而不是哈希表
#1
52
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 Properties
inherit from Map<String, String>
, then the following previously valid code would stop working:
不幸的是,如果他们要追溯使属性继承自Map
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 Properties
should never have inherited from Map
at all. It should instead wrap around Map
, exposing only those features of Map that make sense.
现在,受教育程度最高的观察家们所欣赏的是,财产不应该从地图上继承下来。相反,它应该围绕着地图,只暴露那些有意义的地图特征。
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的琐碎让人讨厌,看看它。
#2
27
It was originally intended that Properties
would indeed extends Hashtable<String,String>
. Unfortunately the implementation of bridge methods caused a problem. Properties
defined in such a way causes javac to generate synthetic methods. Properties
should define, say, a get
method that returns a String
but needs to override a method that returns Object
. So a synthetic bridge method is added.
属性最初的目的是扩展Hashtable
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, Properties
extends Hashtable<Object,Object>
. Similarly Iterable
does not return a (read-only) SimpleIterable
, because that would have added methods to Collection
implementations.
假设你有一个课程是在糟糕的1.4天里写的。您已经在属性中重写了一些方法。但是您没有做的是重写新方法。这会导致无意识的行为。为了避免这些桥接方法,属性扩展了Hashtable ,object>
#3
13
A one-liner (two-liner for no warnings) for creating Map from Properties:
从属性创建映射的一行程序(无警告的两行程序):
@SuppressWarnings({ "unchecked", "rawtypes" })
Map<String, String> sysProps = new HashMap(System.getProperties());
#4
4
Backwards compatibility.
向后兼容性。
#5
2
The reason: Liskov substitution principle and backwards compatibility. Properties
extends Hashtable
and thus must accept all messages that Hashtable
would accept - and that means accepting put(Object, Object)
. And it has to extend plain Hashtable
instead 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替换原理和向后兼容性。属性扩展了Hashtable,因此必须接受Hashtable将接受的所有消息——这意味着接受put(Object, Object)。它必须扩展普通哈希表而不是哈希表