Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);// why wrong?
java.util.Properties是Map的一个实现,而HashMap构造函数接收一个Map类型的param。 但为什么必须明确转换?
答案 0 :(得分:79)
这是因为Properties
extends Hashtable<Object, Object>
(反过来,它实现了Map<Object, Object>
)。您尝试将其反馈到Map<String, String>
。因此它是不相容的。
您需要逐个将字符串属性提供给地图...
例如:
for (final String name: properties.stringPropertyNames())
map.put(name, properties.getProperty(name));
答案 1 :(得分:37)
这样做的有效方法就是按如下方式转换为通用Map:
Properties props = new Properties();
Map<String, String> map = (Map)props;
这会将Map<Object, Object>
转换为原始地图,对编译器来说是“ok”(仅警告)。一旦我们有一个原始Map
,它将转换为Map<String, String>
,它也将是“ok”(另一个警告)。您可以使用注释@SuppressWarnings({ "unchecked", "rawtypes" })
这将起作用,因为在JVM中,对象实际上没有泛型类型。通用类型只是在编译时验证事物的技巧。
如果某个键或值不是String,则会产生ClassCastException
错误。使用当前Properties
实现时,只要您不使用Hashtable<Object,Object>
的超级Properties
中的可变调用方法,就不太可能发生这种情况。
因此,如果不使用您的Properties实例做出令人讨厌的事情,那么这就是您的选择。
答案 2 :(得分:30)
您可以使用Google Guava&#39>:
答案 3 :(得分:26)
这个怎么样?
Map properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);
会引发警告,但无需迭代即可。
答案 4 :(得分:21)
Java 8方式:
properties.entrySet().stream().collect(
Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue().toString()
)
);
答案 5 :(得分:15)
Properties
实施Map<Object, Object>
- 而不是Map<String, String>
。
您正在尝试调用此构造函数:
public HashMap(Map<? extends K,? extends V> m)
...将K
和V
都设为String
。
但Map<Object, Object>
不是Map<? extends String, ? extends String>
...它可以包含非字符串键和值。
这样可行:
Map<Object, Object> map = new HashMap<Object, Object>();
......但它对你没那么有用。
从根本上说,Properties
永远不应该成为HashTable
的子类......这就是问题所在。从v1开始,它始终能够存储非String键和值,尽管这是违背意图的。如果使用了合成,那么API可以仅使用字符串键/值,并且一切都会很好。
你可能想要这样的东西:
Map<String, String> map = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
map.put(key, properties.getProperty(key));
}
答案 6 :(得分:7)
我会使用以下Guava API: com.google.common.collect.Maps#fromProperties
Properties properties = new Properties();
Map<String, String> map = Maps.fromProperties(properties);
答案 7 :(得分:6)
如果知道您的Properties
对象只包含<String, String>
条目,则可以使用原始类型:
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);
答案 8 :(得分:4)
问题在于Properties
实现了Map<Object, Object>
,而HashMap
构造函数需要Map<? extends String, ? extends String>
。
This answer解释了这个(非常反直觉的)决定。简而言之:在Java 5之前,Properties
实现了Map
(因为当时没有泛型)。这意味着您可以将任何 Object
放入Properties
对象中。 This is still in the documenation:
由于
Properties
继承自Hashtable
,put
和putAll
方法 可以应用于Properties
对象。它们的用途很强烈 不鼓励,因为他们允许调用者插入其键或键的条目 值不是String
s。应该使用setProperty
方法。
为了保持与此的兼容性,设计人员别无选择,只能让它在Java 5中继承Map<Object, Object>
。这是一个令人遗憾的结果,即努力实现完全向后兼容性,这使得新代码不必要地复杂化。
如果您只在Properties
对象中使用字符串属性,那么应该能够在构造函数中使用未经检查的强制转换:
Map<String, String> map = new HashMap<String, String>( (Map<String, String>) properties);
或没有任何副本:
Map<String, String> map = (Map<String, String>) properties;
答案 9 :(得分:2)
这只是因为HashMap的构造函数需要一个Map泛型类型的arg,而Properties实现了Map。
这会有效,但有警告
Properties properties = new Properties();
Map<String, String> map = new HashMap(properties);
答案 10 :(得分:1)
您可以使用此:
Map<String, String> map = new HashMap<>();
props.forEach((key, value) -> map.put(key.toString(), value.toString()));
答案 11 :(得分:0)
首先,
属性类基于Hashtable而不是Hashmap。 Properties类基本上扩展了Hashtable
HashMap类中没有这样的构造函数,它接受一个属性对象并返回一个hashmap对象。所以你所做的不正确。您应该能够将属性对象强制转换为哈希表引用。
答案 12 :(得分:0)
我用这个:
for (Map.Entry<Object, Object> entry:properties.entrySet()) {
map.put((String) entry.getKey(), (String) entry.getValue());
}
答案 13 :(得分:0)
当我看到Spring框架源代码时,我找到了这种方式
Properties props = getPropertiesFromSomeWhere();
// change properties to map
Map<String,String> map = new HashMap(props)