为什么Java中的某些方法会修改原始值而某些方法却没有?

时间:2009-02-09 02:33:45

标签: 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
===> [Java, Groovy, JRuby]


languages.sort()
===> [Groovy, JRuby, Java]
println languages
===> [Groovy, JRuby, Java]

5 个答案:

答案 0 :(得分:11)

String在Java中是不可变的。任何“修改”String的方法都必须返回String的新实例。

来自Java API Specifications for the String class

  

字符串是不变的;他们的价值观   它们之后无法改变   创建

The Java Language SpecificationsSection 4.3.3: The Class String中定义了此行为。


对编辑的回复:

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

根据我从查看示例中的理解,似乎有一个languages列表正在reverse - ed和sort - ed - 这些操作本身不会修改列表中包含的String个对象,但是对列表本身起作用。

列表的方式返回一个新列表,或者它如何修改或不修改列表与String个对象本身的行为无关。

答案 1 :(得分:3)

Java API是由许多不同的人设计的,因此很难保持一致性。我相信人们普遍认为不变性(即内部状态不应该改变)现在是一件好事,至少在价值对象方面是这样。

另一个类似的问题是,“为什么索引有时基于0(大部分时间),有时基于1(JDBC)。”同样,我认为这是另一种情况,即API过于宽泛,不同API的开发人员没有协调(尽管如此,如果有人知道JDBC基于1的真正原因,请告诉我)。

答案 2 :(得分:2)

我认为你的意思是str.concat("ness")。在这个带有String s的特定示例中,没有方法可以改变对象,因为String被设计为不可变。在库中,您会发现许多方法可以改变对象的状态(例如StringBuffer.replace()),而其他方法则不会(例如String.replace())。您必须仔细阅读API以确定是哪种情况。最终,这是图书馆设计师的选择,他必须考虑功能,易用性以及与他或她正在撰写的软件包相关的约定。

答案 3 :(得分:0)

因为有不可变和可变的类。

另一个答案指出,

String是一个不可变的类。创建String后,它们的值始终保持不变。

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

对编辑的回应

对于你的groovy例子,可能是它的设计师坐下来注意到更多时候会想要一个包含反转结果的新列表,并保持旧列表不变。 (为什么?我不知道)。另一方面,他们可能已经注意到有更多情况下您不希望有一个包含排序结果的新列表。所以它就地完成了它的工作。但我不知道,之前没有使用过groovy,所以只是一个猜测。

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

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

答案 4 :(得分:0)

在某种程度上,这也与编程风格有关。不更改原始对象并创建新副本以反映更改是安全编程的习惯用法。我相信Josh Bloch在他的“Effective Java”(第一版)一书中提到过它。虽然我不记得他用过的确切术语。

在String的情况下,它返回一个新对象,因为String是不可变的。但是,在Java API中,您将看到原始对象发生更改的位置以及返回新对象的某些位置。正如之前有人指出的那样,这是因为不同的人都在使用API​​,他们带来了自己的编程风格。

稍微不同的说明:保持对象不可变会增加代码的安全性,并且它还允许我们以某种方式编码。

(new Date()).add(new Month(7)).add(new Day(4))

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

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