将java.util.Properties转换为HashMap <string,string>
Properties properties = new Properties(); Map<String, String> map = new HashMap<String, String>(properties);// why wrong?
java.util.Properties是Map的一个实现,而HashMap的构造函数接收一个Maptypes的参数。 但为什么要明确转换?
这是因为Properties
扩展了Hashtable<Object, Object>
(反过来,它实现了Map<Object, Object>
)。 您尝试将其提供给Map<String, String>
。 因此它是不相容的。
您需要将string属性逐个送入您的地图…
例如:
for (final String name: properties.stringPropertyNames()) map.put(name, properties.getProperty(name));
这个怎么样?
Map properties = new Properties(); Map<String, String> map = new HashMap<String, String>(properties);
会导致警告,但没有重复的工作。
要做到这一点的有效方法只是投射到一个通用的地图如下:
Properties props = new Properties(); Map<String, String> map = (Map)props;
这将把一个Map<Object, Object>
转换为一个原始的Map,编译器(只有警告)为“ok”。 一旦我们有一个原始的Map
,它将投影到Map<String, String>
,它也将是“好”(另一个警告)。 你可以通过注释@SuppressWarnings({ "unchecked", "rawtypes" })
忽略它们。
这将工作,因为在JVM中,该对象实际上并不具有genericstypes。 genericstypes只是在编译时validation事物的一个技巧。
如果某个键或值不是一个string,它将产生一个ClassCastException
错误。 使用当前的Properties
实现,这是不太可能发生的,只要你不使用Properties
的超级Hashtable<Object,Object>
中的可变调用方法。
所以,如果不用你的Properties实例做一些令人讨厌的事情,这就是要走的路。
你可以使用Google Guava的:
com.google.common.collect.Maps.fromProperties(属性)
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<? extends String, ? extends String>
Map<? extends String, ? extends String>
…它可以包含非string键和值。
这将工作:
Map<Object, Object> map = new HashMap<Object, Object>();
…但它不会对你有用。
从根本上说, Properties
不应该成为HashTable
的子类…这就是问题所在。 从v1开始,它始终能够存储非string键和值,尽pipe这是违背意图的。 如果已经使用了组合,API可能只能使用string键/值,并且一切都会好的。
你可能想要这样的东西:
Map<String, String> map = new HashMap<String, String>(); for (String key : properties.stringPropertyNames()) { map.put(key, properties.getProperty(key)); }
Java 8的方式:
properties.entrySet().stream().collect( Collectors.toMap( e -> e.getKey().toString(), e -> e.getValue().toString() ) );
如果您知道您的Properties
对象只包含<String, String>
条目,则可以使用原始types:
Properties properties = new Properties(); Map<String, String> map = new HashMap<String, String>((Map) properties);
问题是Properties
实现Map<Object, Object>
,而HashMap
构造函数需要一个Map<? extends String, ? extends String>
Map<? extends String, ? extends String>
Map<? extends String, ? extends String>
。
这个答案解释了这个(非常直观的)决定。 简而言之:在Java 5之前, Properties
实现了Map
(因为当时没有generics)。 这意味着你可以把任何 Object
放在Properties
对象中。 这仍然是在文件中:
由于
Properties
从Hashtable
inheritance,put
和putAll
方法可以应用于Properties
对象。 强烈build议不要使用它们,因为它们允许调用者插入其键或值不是String
的条目。 应该使用setProperty
方法。
为了保持兼容性,devise人员没有别的select,只能inheritanceJava 5中的Map<Object, Object>
。这是一个不幸的结果,它致力于完全向后兼容,这使得新代码不必要的复杂化。
如果你只在你的Properties
对象中使用过string属性,你应该可以在构造函数中使用未经检查的强制转换:
Map<String, String> map = new HashMap<String, String>( (Map<String, String>) properties);
或没有任何副本:
Map<String, String> map = (Map<String, String>) properties;
我会使用以下Guava API: com.google.common.collect.Maps#fromProperties
Properties properties = new Properties(); Map<String, String> map = Maps.fromProperties(properties);
这只是因为HashMap的构造函数需要一个Mapgenericstypes的属性和Properties实现Map。
这将工作,但有警告
Properties properties = new Properties(); Map<String, String> map = new HashMap(properties);
首先,
Properties类基于Hashtable而不是Hashmap。 Properties类基本上扩展了Hashtable
HashMap类中没有这样的构造函数,它需要一个属性对象并返回一个HashMap对象。 所以你在做什么是不正确的。 您应该能够将属性的对象转换为散列表引用。