Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);// why wrong?
java.util.Properties
是 的一个实现java.util.Map
,并且java.util.HashMap
的构造函数接收一个Map
类型参数。那么,为什么必须显式转换呢?
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);// why wrong?
java.util.Properties
是 的一个实现java.util.Map
,并且java.util.HashMap
的构造函数接收一个Map
类型参数。那么,为什么必须显式转换呢?
这是因为Properties
extendsHashtable<Object, Object>
(反过来,实现Map<Object, Object>
)。您尝试将其输入到Map<String, String>
. 因此是不兼容的。
您需要将字符串属性一一输入到地图中......
例如:
for (final String name: properties.stringPropertyNames())
map.put(name, properties.getProperty(name));
做到这一点的有效方法就是转换为通用 Map 如下:
Properties props = new Properties();
Map<String, String> map = (Map)props;
这会将 a 转换Map<Object, Object>
为原始 Map,这对于编译器来说是“可以的”(仅警告)。一旦我们有了一个 raw Map
,它就会被转换成Map<String, String>
它也将是“好的”(另一个警告)。您可以使用注释忽略它们@SuppressWarnings({ "unchecked", "rawtypes" })
这将起作用,因为在 JVM 中,对象实际上并没有泛型类型。泛型类型只是在编译时验证事物的一种技巧。
如果某个键或值不是字符串,则会产生ClassCastException
错误。在当前的Properties
实现中,这不太可能发生,只要您不Hashtable<Object,Object>
使用Properties
.
所以,如果不要对你的 Properties 实例做讨厌的事情,这就是要走的路。
您可以使用 Google Guava 的:
这个怎么样?
Map properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);
将导致警告,但无需迭代即可工作。
Java 8 方式:
properties.entrySet().stream().collect(
Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue().toString()
)
);
Properties
实现Map<Object, Object>
- 不是Map<String, String>
。
您正在尝试调用此构造函数:
public HashMap(Map<? extends K,? extends V> m)
... withK
和V
both as String
。
但Map<Object, Object>
is not a Map<? extends String, ? extends String>
... 它可以包含非字符串键和值。
这会起作用:
Map<Object, Object> map = new HashMap<Object, Object>();
...但它不会对你有用。
从根本上说,Properties
永远不应该成为HashTable
......的子类,这就是问题所在。从 v1 开始,它总是能够存储非字符串键和值,尽管这违背了本意。如果改为使用组合,API 可能只能使用字符串键/值,一切都会很好。
你可能想要这样的东西:
Map<String, String> map = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
map.put(key, properties.getProperty(key));
}
我会使用以下番石榴 API: com.google.common.collect.Maps#fromProperties
Properties properties = new Properties();
Map<String, String> map = Maps.fromProperties(properties);
如果您知道您的Properties
对象仅包含<String, String>
条目,则可以使用原始类型:
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);
问题在于Properties
实现Map<Object, Object>
,而HashMap
构造函数需要一个Map<? extends String, ? extends String>
.
这个答案解释了这个(非常违反直觉的)决定。简而言之:在 Java 5 之前Properties
实现Map
(因为当时没有泛型)。这意味着您可以将任何 Object
内容放入Properties
对象中。这仍在文档中:
因为
Properties
继承自Hashtable
,put
和putAll
方法可以应用于Properties
对象。强烈建议不要使用它们,因为它们允许调用者插入键或值不是String
s 的条目。setProperty
应该改用该方法。
为了保持与此的兼容性,设计者别无选择,只能Map<Object, Object>
在 Java 5 中继承它。这是努力实现完全向后兼容性的不幸结果,这使得新代码不必要地复杂化。
如果您只在Properties
对象中使用字符串属性,您应该能够在构造函数中使用未经检查的强制转换:
Map<String, String> map = new HashMap<String, String>( (Map<String, String>) properties);
或没有任何副本:
Map<String, String> map = (Map<String, String>) properties;
这只是因为 HashMap 的构造函数需要 Map 泛型类型的 arg 并且 Properties 实现了 Map。
这将起作用,但会发出警告
Properties properties = new Properties();
Map<String, String> map = new HashMap(properties);
你可以使用这个:
Map<String, String> map = new HashMap<>();
props.forEach((key, value) -> map.put(key.toString(), value.toString()));
第一件事,
属性类基于 Hashtable 而不是 Hashmap。属性类基本上扩展了 Hashtable
HashMap 类中没有这样的构造函数,它接受一个属性对象并返回一个 hashmap 对象。所以你在做什么是不正确的。您应该能够将属性对象转换为哈希表引用。
当我看到Spring框架源代码时,我发现了这种方式
Properties props = getPropertiesFromSomeWhere();
// change properties to map
Map<String,String> map = new HashMap(props)
我用这个:
for (Map.Entry<Object, Object> entry:properties.entrySet()) {
map.put((String) entry.getKey(), (String) entry.getValue());
}