java更改方法内的字符串,该字符串应位于方法外
首先,我想展示我的代码:
public static void main(String[] args)
{
Map<String,Integer> map = new LinkedHashMap<String,Integer>();
map.put("bye",0);
map.put("Hello",1);
System.out.println(Arrays.toString(map(map, new BiConsumer<String,Integer>(){
@Override
public void accept(String s, Integer i){
s=s+"s";
}
})));
}
public static String[] map(Map<String,Integer> m, BiConsumer<String,Integer> bif){
String[] key = m.keySet().toArray(new String[0]);
String[] entries = new String[m.size()];
for (int i = 0; i < m.size(); i++) {
bif.accept(key[i],m.get(key[i]));
entries[i] = key[i] + ", " + m.get(key[i]);
}
return entries;
}
如您所见,我想开发一种接受映射的方法<;字符串,整数>;和双消费者<;字符串,整数>;,这就是传递函数对映射中的每个键和值所要做的,并最终返回一个字符串数组
有人可能会说:一种大致上与forEach相同的方法: https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html#forEach-java.util.function.BiConsumer-
我能够添加BiConsumer接口,因为它不依赖于其他Java8类
我需要在不改变以下代码中任何内容的情况下开发此方法,并且仅使用Java 7:
System.out.println(Arrays.toString(map(map, new BiConsumer<String,Integer>(){
@Override
public void accept(String s, Integer i){
s=s+"s";
}
})));
预期结果:
[byes, 0, Hellos, 1]
但我得到了:
[bye, 0, Hello, 1]
因此,我不知道是否应该在方法外部的方法中更改字符串
你有什么想法吗
# 1 楼答案
不幸的是,正如您可能经历的那样,Java字符串是不可变的。这意味着,每当您编写类似
s = s + s;
的内容时,您都在创建一个新对象。此外,Java总是按值传递。因此,任何对象引用(如accept方法中的字符串)也会按值传递。这意味着做一些事情,比如-也不会更改方法外部的引用
有一些方法可以解决这个问题,但这有点麻烦。实际上,您将字符串引用存储在一个新类中,然后对该类进行操作。下面是一个演示:
显然,您可以根据您的用例对此进行改进(例如,为StringRefContainer类重写toString、hashcode、equals等,或者更改/添加访问说明符以适合您的设计,等等)
# 2 楼答案
这一行:
创建一个新的
String
并将其存储在s
。在赋值之前,s
与keys[i]
存储对同一对象的引用。赋值之后,因为s
引用了一个新对象,与keys[i]
引用的对象完全无关。事实上,您不能通过更改s
来更改keys[i]
中的字符串,即使s
在方法的开头引用了与keys[i]
相同的对象。这是因为String
是不可变的。另见:Immutability of Strings in Java您可以做的是让
BiConsumer
返回创建的新字符串,并在调用者一侧,将返回的字符串分配给keys[i]
。在这一点上,我们不再有一个BiConsumer<String, Integer>
,而是一个BiFunction<String, Integer, String>
:map
看起来像这样:你会这样称呼它: