在Java中将HashMap.toString()转换回HashMap

36

我在Java的HashMap中放置了一个键值对,并使用toString()方法将其转换为String

那么,是否可以将这个String表示形式转换回HashMap对象,并使用其相应的键检索值?

谢谢


1
通常而言,object->toString()是一个单向的转换,有时可以通过toString()->object实现,但并非所有类都可以。最好使用objectOutputStream,如某些答案中所述。 - iirekm
12个回答

23

如果toString()包含恢复对象所需的所有数据,则它将起作用。例如,对于字符串映射(其中字符串用作键和值),它将起作用:

// create map
Map<String, String> map = new HashMap<String, String>();
// populate the map

// create string representation
String str = map.toString();

// use properties to restore the map
Properties props = new Properties();
props.load(new StringReader(str.substring(1, str.length() - 1).replace(", ", "\n")));       
Map<String, String> map2 = new HashMap<String, String>();
for (Map.Entry<Object, Object> e : props.entrySet()) {
    map2.put((String)e.getKey(), (String)e.getValue());
}

这个有效,尽管我真的不理解为什么需要这样做。


1
map.put("k=2", "v=2"); System.out.println(map2.get("k=2")); 输出结果为:null - seyed
@seyed 在将其转换为字符串之前,您需要对键和值进行编码(例如URLencode),并在将字符串解除转换后解码,以避免出现任何语法问题。 - fuggi

15

toString()方法依赖于toString()的实现,但在大多数情况下会有信息丢失。

这里没有无损解决方案,但更好的解决方法是使用对象序列化。

将对象序列化为字符串。

private static String serialize(Serializable o) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(o);
    oos.close();
    return Base64.getEncoder().encodeToString(baos.toByteArray());
}
将字符串反序列化为对象
private static Object deserialize(String s) throws IOException,
        ClassNotFoundException {
    byte[] data = Base64.getDecoder().decode(s);
    ObjectInputStream ois = new ObjectInputStream(
            new ByteArrayInputStream(data));
    Object o = ois.readObject();
    ois.close();
    return o;
}

如果用户对象具有瞬态字段,那么在过程中它们将会丢失。


旧答案


一旦使用toString()方法将HashMap转换为字符串,就不能通过该字符串将其转换回HashMap,它只是其字符串表示形式。

您可以将HashMap的引用传递给方法,或者对其进行序列化处理。

这里是toString()方法的描述(链接)这里提供了带有解释的序列化示例代码。

要将HashMap作为参数传递给方法,请参考下面的代码:

public void sayHello(Map m){

}
//calling block  
Map  hm = new HashMap();
sayHello(hm);

请问,您能详细解释一下这个吗? - Sameek Mishra
1
这个答案毫无意义。 - We are Borg
1
@WeareBorg,谢谢您指出来,这是我作为初级工程师写的8年前的答案。让我重新写一下。 - jmj

6

你不能直接这样做,但我用以下疯狂的方式实现了...

基本思路是,首先需要将HashMap String转换为Json,然后可以使用Gson/Genson等工具将Json反序列化为HashMap。

@SuppressWarnings("unchecked")
private HashMap<String, Object> toHashMap(String s) {
    HashMap<String, Object> map = null;
    try {
        map = new Genson().deserialize(toJson(s), HashMap.class);
    } catch (TransformationException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return map;
}

private String toJson(String s) {
    s = s.substring(0, s.length()).replace("{", "{\"");
    s = s.substring(0, s.length()).replace("}", "\"}");
    s = s.substring(0, s.length()).replace(", ", "\", \"");
    s = s.substring(0, s.length()).replace("=", "\":\"");
    s = s.substring(0, s.length()).replace("\"[", "[");
    s = s.substring(0, s.length()).replace("]\"", "]");
    s = s.substring(0, s.length()).replace("}\", \"{", "}, {");
    return s;
}

implementation...

HashMap<String, Object> map = new HashMap<String, Object>();
map.put("Name", "Suleman");
map.put("Country", "Pakistan");
String s = map.toString();
HashMap<String, Object> newMap = toHashMap(s);
System.out.println(newMap);

5
我使用toString()方法将HashMap转换为字符串,并将其传递给另一个方法,该方法接受一个字符串并将其转换为HashMap对象。这是一种非常糟糕的传递HashMap的方式。在理论上可以工作,但存在太多可能出错的地方(而且性能非常低)。显然,在你的情况下出了一些问题。我们无法在没有看到你的代码的情况下确定问题所在。但一个更好的解决方案是改变"另一个方法"的实现方式,使其仅接受HashMap作为参数而不是它的字符串表示形式。

2
我认为他的意思是不同实例调用不同的方法。例如,A 实例将 Map 序列化为字符串,而 B 实例必须将字符串反序列化为 Map 对象。 - TheRealChx101

5
你可以使用谷歌的开源Java库"GSON"来实现这个功能,
示例输入(Map.toString):{name=Bane, id=20}
要再次插入到HashMap中,你可以使用以下代码:
yourMap = new Gson().fromJson(yourString, HashMap.class);

就是这样。
(在Jackson Library映射器中,它会产生异常“期望双引号来开始字段名”)

3

你尝试了什么?

objectOutputStream.writeObject(hashMap);

如果hashMap中的所有对象都实现了Serializable接口,那么应该可以正常工作。


3

您无法从字符串恢复为对象。因此,您需要执行以下操作:

HashMap<K, V> map = new HashMap<K, V>();

//Write:
OutputStream os = new FileOutputStream(fileName.ser);
ObjectOutput oo = new ObjectOutputStream(os);
oo.writeObject(map);
oo.close();

//Read:
InputStream is = new FileInputStream(fileName.ser);
ObjectInput oi = new ObjectInputStream(is);
HashMap<K, V> newMap = oi.readObject();
oi.close();

3

你是否被限制只能使用 HashMap

为什么不能更加灵活地使用 JSONObject?使用它可以做很多事情。

你可以把 String jsonString 转换成 JSONObject jsonObj

JSONObject jsonObj = new JSONObject(jsonString);
Iterator it = jsonObj.keys();

while(it.hasNext())
{
    String key = it.next().toString();
    String value = jsonObj.get(key).toString();
}

2
使用ByteStream可以将字符串转换,但在处理大字符串时可能会遇到OutOfMemory异常。Baeldung在他的文章中提供了一些不错的解决方案:https://www.baeldung.com/java-map-to-string-conversion 使用StringBuilder:
public String convertWithIteration(Map<Integer, ?> map) {
StringBuilder mapAsString = new StringBuilder("{");
for (Integer key : map.keySet()) {
    mapAsString.append(key + "=" + map.get(key) + ", ");
}
mapAsString.delete(mapAsString.length()-2, mapAsString.length()).append("}");
return mapAsString.toString(); }

请注意,Lambda表达式仅在语言级别为8及以上时可用。 使用Stream:
public String convertWithStream(Map<Integer, ?> map) {
String mapAsString = map.keySet().stream()
  .map(key -> key + "=" + map.get(key))
  .collect(Collectors.joining(", ", "{", "}"));
return mapAsString; }

使用Stream将字符串转换回Map:

public Map<String, String> convertWithStream(String mapAsString) {
Map<String, String> map = Arrays.stream(mapAsString.split(","))
  .map(entry -> entry.split("="))
  .collect(Collectors.toMap(entry -> entry[0], entry -> entry[1]));
return map; }

1

我希望您实际上需要通过传递哈希映射键从字符串中获取值。如果是这种情况,那么我们就不必将其转换回Hashmap。使用以下方法,您将能够像从Hashmap本身检索一样获取值。

String string = hash.toString();
String result = getValueFromStringOfHashMap(string, "my_key");

/**
 * To get a value from string of hashmap by passing key that existed in Hashmap before converting to String.
 * Sample string: {fld_category=Principal category, test=test 1, fld_categoryID=1}
 *
 * @param string
 * @param key
 * @return value
 */
public static String getValueFromStringOfHashMap(String string, String key) {


    int start_index = string.indexOf(key) + key.length() + 1;
    int end_index = string.indexOf(",", start_index);
    if (end_index == -1) { // because last key value pair doesn't have trailing comma (,)
        end_index = string.indexOf("}");
    }
    String value = string.substring(start_index, end_index);

    return value;
}

这对我来说做得到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接