101
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类型参数。那么,为什么必须显式转换呢?

4

14 回答 14

99

这是因为PropertiesextendsHashtable<Object, Object>(反过来,实现Map<Object, Object>)。您尝试将其输入到Map<String, String>. 因此是不兼容的。

您需要将字符串属性一一输入到地图中......

例如:

for (final String name: properties.stringPropertyNames())
    map.put(name, properties.getProperty(name));
于 2013-06-20T08:54:53.197 回答
52

做到这一点的有效方法就是转换为通用 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 实例做讨厌的事情,这就是要走的路。

于 2014-10-09T11:07:03.827 回答
37

您可以使用 Google Guava 的:

com.google.common.collect.Maps.fromProperties(属性)

于 2015-03-31T02:46:47.877 回答
28

这个怎么样?

   Map properties = new Properties();
   Map<String, String> map = new HashMap<String, String>(properties);

将导致警告,但无需迭代即可工作。

于 2013-06-20T08:59:25.790 回答
28

Java 8 方式:

properties.entrySet().stream().collect(
    Collectors.toMap(
         e -> e.getKey().toString(),
         e -> e.getValue().toString()
    )
);
于 2016-04-30T02:08:25.503 回答
18

Properties实现Map<Object, Object>- 不是Map<String, String>

您正在尝试调用此构造函数:

public HashMap(Map<? extends K,? extends V> m)

... withKVboth 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));
}
于 2013-06-20T08:58:14.523 回答
10

我会使用以下番石榴 API: com.google.common.collect.Maps#fromProperties

Properties properties = new Properties();
Map<String, String> map = Maps.fromProperties(properties);
于 2016-09-26T12:31:53.787 回答
8

如果您知道您的Properties对象仅包含<String, String>条目,则可以使用原始类型:

Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);
于 2013-06-20T08:58:26.260 回答
5

问题在于Properties实现Map<Object, Object>,而HashMap构造函数需要一个Map<? extends String, ? extends String>.

这个答案解释了这个(非常违反直觉的)决定。简而言之:在 Java 5 之前Properties实现Map(因为当时没有泛型)。这意味着您可以将任何 Object内容放入Properties对象中。这仍在文档中:

因为Properties继承自HashtableputputAll方法可以应用于Properties对象。强烈建议不要使用它们,因为它们允许调用者插入键或值不是Strings 的条目。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;
于 2013-06-20T08:58:30.650 回答
2

这只是因为 HashMap 的构造函数需要 Map 泛型类型的 arg 并且 Properties 实现了 Map。

这将起作用,但会发出警告

    Properties properties = new Properties();
    Map<String, String> map = new HashMap(properties);
于 2013-06-20T09:03:19.950 回答
1

你可以使用这个:

Map<String, String> map = new HashMap<>();

props.forEach((key, value) -> map.put(key.toString(), value.toString()));
于 2020-03-03T05:15:55.470 回答
0

第一件事,

属性类基于 Hashtable 而不是 Hashmap。属性类基本上扩展了 Hashtable

HashMap 类中没有这样的构造函数,它接受一个属性对象并返回一个 hashmap 对象。所以你在做什么是不正确的。您应该能够将属性对象转换为哈希表引用。

于 2013-06-20T08:54:51.763 回答
0

当我看到Spring框架源代码时,我发现了这种方式

Properties props = getPropertiesFromSomeWhere();
 // change properties to map
Map<String,String> map = new HashMap(props)
于 2021-02-03T10:10:53.300 回答
0

我用这个:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
于 2018-07-17T11:25:06.833 回答