为什么Java中的某些方法修改原始值,而某些方法不修改?

为什么Java中的某些方法修改原始值,而某些方法不修改?,java,groovy,Java,Groovy,方法Concat()不修改原始值。它返回一个新值。 像这样: String str = "good"; str.concat("ness"); System.out.println(str); //"good" 但有些方法会修改原始值。为什么? 在Groovy中: def languages = ["Java", "Groovy", "JRuby"] languages.reverse() ===> [JRuby, Groovy, Java] println languages ==

方法Concat()不修改原始值。它返回一个新值。
像这样:

String str = "good";
str.concat("ness");
System.out.println(str);   //"good"
但有些方法会修改原始值。为什么?

在Groovy中:

def languages = ["Java", "Groovy", "JRuby"]
languages.reverse()
===> [JRuby, Groovy, Java]
println languages
===> [Java, Groovy, JRuby]


languages.sort()
===> [Groovy, JRuby, Java]
println languages
===> [Groovy, JRuby, Java]
在Java中是不可变的。任何“修改”
字符串的方法都必须返回
字符串的新实例

从:

字符串是常量;他们的价值观 更改后无法更改 创造

在中定义此行为


对编辑的响应:

似乎添加了Groovy中的一个示例。(我以前没有使用过Groovy,因此我对它的理解可能不正确。)

从我看示例的理解来看,似乎有一个
语言
列表被
反向
-ed和
排序
-ed——这些操作本身并不修改列表中包含的
字符串
对象,而是作用于列表本身


列表返回新列表的方式,或者它修改或不修改列表的方式与
字符串
对象本身的行为无关

因为存在不可变类和可变类

String
,正如另一个答案所指出的,是一个不可变的类。创建字符串后,它们的值始终保持不变

如果您有一个
ArrayList
对象,则可以使用其
add
函数将另一个整数添加到列表中。
add
功能将更改列表,而不是返回新列表。数组列表是可变的

对编辑的响应

对于groovy示例,它的设计者可能会坐下来注意到,更多情况下,人们需要一个包含相反结果的新列表,并保持旧列表不变。(为什么?我不知道)。另一方面,他们可能已经注意到,在更多的情况下,您不希望有一个包含排序结果的新列表。因此,它在适当的地方完成了它的工作。但我不知道,以前也没用过groovy,所以只是一个猜测

在Ruby中,我听说有这样一个概念:在原地更改对象的函数后面会写一个感叹号,而作为新对象返回结果的函数没有感叹号:

newObj = obj.sort(); // new sorted list is returned
obj.sort!(); // obj is sorted in-place

JavaAPI是由许多不同的人设计的,因此很难保持所有内容的一致性。我相信人们现在普遍接受不变性(即内部状态不应该改变)是一件好事,至少在涉及价值对象时是这样


另一个类似的问题是,“为什么索引有时是基于0的(大多数情况下),有时是基于1的(JDBC)。”同样,我认为这是API过于宽泛的另一种情况,不同API的开发人员不协调(不过我可能错了,如果有人知道JDBC基于1的真正原因,请告诉我).

我想你指的是
str.concat(“ness”)
。在这个使用
String
s的特定示例中,没有任何方法可以变异对象,因为
String
s被设计为不可变的。在库中,您将发现许多方法可以改变对象的状态(例如),而其他方法则不能(例如)。你必须仔细阅读这本书才能确定是哪一种情况。最终,这是一个由图书馆设计者做出的选择,他必须考虑与他或她正在编写的包相关的功能性、易用性和约定。

这在一定程度上也与编程风格有关。不更改原始对象并创建新副本以反映更改是安全编程的习惯用法。我相信Josh Bloch在他的书《有效Java》(第一版)中提到了这一点。虽然我记不起他用的确切术语

对于String,它返回一个新对象,因为String是不可变的。但是,在JavaAPI中,您将看到一些地方更改了原始对象,一些地方返回了新对象。正如前面有人指出的那样,这是因为不同的人使用了API,他们带来了自己的编程风格

有一点不同:保持对象不变增加了代码的安全性,也允许我们以某种方式编写代码


(新日期()).add(新月份(7)).add(新日期(4))

如果Date上的每个方法都返回一个新对象,而不是更改它自己的状态,那么我们可以编写这样的代码。这使得程序非常可读


但是,如果对象较大,保持对象不变可能会降低系统的性能。

示例选择不当。修改输入字符串的方法在哪里?正如您所说,collect不会修改其输入,但println也不会修改。我现在理解了这个问题。不,groovy示例的要点似乎是方法reverse()不修改对象(而是返回一个新对象),而sort()修改对象。@dehmann:啊,我错过了这一部分!谢谢你指出这一点@dehmann:为什么方法reverse()返回一个新对象,sort()修改它?如果我看不到API,我们能得到什么规则吗?如果有一个约定说:如果一个方法不需要访问对象的内部并且不改变对象的状态,那么它就不应该是成员(或者应该是静态的?)String。replace()似乎是一个很好的例子。我同意。这肯定会使API更加一致。基于1的JDBC实际上是个例外,标准是基于0的。也许有一些数据库API正在显示出来。