Java与Python中的不可变类型

时间:2014-01-03 02:02:10

标签: java python immutability

String a = new String("Wow");
String b = new String("Wow");
String sameA = a;

boolean r1 = a == b;      // This is false, since a and b are not the same object
boolean r2 = a.equals(b); // This is true, since a and b are logically equals
boolean r3 = a == sameA;  // This is true, since a and sameA are really the same object

为什么会这样?因为字符串是不可变的,所以ab不指向相同的字符串吗?例如,如果我在Python中做同样的事情,这就是我得到的:

a = "wow"
b = "wow"
a is b #is True because (I thought) both variables point to the same immutable string
a == b #is True because they are logically equivalent

我假设Java的==与Python的'is'相同,而Java的.equals与Python的='相同,在这种情况下,两个代码块相互矛盾。

我还怀疑这可能与Java不将字符串视为原语这一事实有关吗?

3 个答案:

答案 0 :(得分:4)

  

因为字符串是不可变的,所以a和b不是指向同一个字符串吗?

没有。在Java中,它们不是因为你明确要求它从文字中创建一个new String对象,然后用相同的文字创建另一个new String,这可以保证你得到两个不同的对象。 (在你的Python测试中,你会得到完全相同的结果,尽管语言无法保证 - 详见下文。)


  

我假设Java的==与Python的'is'相同,而Java的.equals与Python的相同==

这个问题足够接近真实。

  

在这种情况下,两个代码块相互矛盾。

不,他们没有。您将两个测试转换为Python,并获得与两个相应Java测试完全相同的结果。你根本没有翻译第三个测试,所以没有什么可以与任何东西相矛盾。

让我们重复你的Java:

String a = new String("Wow");
String b = new String("Wow");
String sameA = a;

boolean r1 = a == b;      // This is false, since a and b are not the same object
boolean r2 = a.equals(b); // This is true, since a and b are logically equals
boolean r3 = a == sameA;  // This is true, since a and sameA are really the same object

...并将其更贴近Python:

a = "Wow"[:]
b = "Wow"[:]
sameA = a

r1 = a is b               # This is False, since a and b are not the same object
r2 = a == b               # This is True, since a and b are logically equals
r3 = a is sameA           # This is True, since a and sameA are really the same object

[:]与原始代码中的new相匹配。您明确要求Java从文字String中创建一个新的"Wow"对象。在Python中,没有办法明确要求一个新对象,但你总是可以要求一个足够接近的副本(只要你不关心你可能会创建一些额外的字符串作为垃圾)立即收集)。


但是,如果删除[:],您通常会得到相同的结果 - 就像您在自己的测试中看到的那样。您True a == bFalse a is b a = "Wow" b = "Wow" sameA = a r1 = a is b # This is False, since a and b are not the same object r2 = a == b # This is True, since a and b are logically equals r3 = a is sameA # This is True, since a and sameA are really the same object 。以这种方式重复测试:

a is b

在你的评论中,你说new String实际上是真的,而不是假的。

如上所述,这也是完全合法的。虽然Java要求String创建一个新的String对象,但Python中没有任何内容要求两次评估相同的字符串文字必须创建两个单独的字符串对象,甚至复制字符串对象必须创建一个新的字符串对象。请参阅下文了解更多信息。


  

我还怀疑这可能与Java不将字符串视为原语有关吗?

间接地,它与Java不将字符串视为原语这一事实有关,而且与Python不会像其他类型的文字一样处理字符串文字这一事实有关。

在Java中,由于new String不是基元,因此您可以选择显式创建"Wow"。而你这样做。因此,它不会与之前的任何实例相同。它们都是不可变的实例这一事实无关紧要;如果有任何可见的方式,Java不允许将单独的对象折叠为单个对象。

在Python中,[:]是一个文字,你不是要求它创建一个新的字符串。字符串是不可变的,Python 允许以Java不能的方式折叠单独的不可变内置对象。所以它可以将两个文字组合成一个。即使使用0,也可以将新副本折叠为原始副本。对于小整数,它通常会这样做 - 尝试使用copy.copy(0)(使用"Wow"测试显式复制)而不是a is b进行相同的测试,看看会发生什么。但是主要的Python实现经常碰巧不对字符串执行此操作,因此您最终会得到单独的对象,因此您可以获得与Java相同的结果。


这在实践中意味着,使用像您这样的代码,无论是否有明确的副本,a is not btimeit都是完全合法且合理的事情,因此您的代码永远不应该依赖 一个是真的。幸运的是,没有理由这样做。 (如果您认为性能可能是一个很好的理由,请尝试在a is ba == b上调用{{1}},然后您会找到55.3ns与61.0ns之类的内容。)


要记住的最后一件事:Python和Java是非常不同的语言,所以看起来类似的代码有时行为非常不同(或者看起来非常不同的代码有时表现相似)也不应该令人惊讶。英语规定什么时候使用这个与日本的kore vs. sore vs.规则不一样的事实并不奇怪,这只是你学习日语时(或者当你学习英语时)必须学习的东西

答案 1 :(得分:0)

在Java new运算符中,总是返回一个新对象,该对象在内存中占据自己的位置并具有唯一的指针。

答案 2 :(得分:0)

不变性:对象不可更改。

到你的问题

String a = new String("Wow");
String b = new String("Wow");
String sameA = a;
boolean r1 = a == b;      // This is false, since a and b are not the same object

引用变量a和b不是指同一个Object。当使用new运算符创建String时,对于相同的字符串Literal,会在堆中保留全新的内存空间。

如果String Pool没有使字符串不可变的功能,那么字符串池中有一个字符串对象/ literal已被许多引用变量引用,如果其中任何一个更改了值,则其他引用变量将自动更改。例如

String firstString= "xyzabc";
String secondString= "xyzabc"; 

现在String secondString名为"xyzabc".toUpperCase(),它将同一个对象更改为“XYZABC”,因此A也将是“XYZABC”,这是不可取的。

boolean r2 = a.equals(b); // This is true, since a and b are logically equals

//Here literal i.e values of two different object is checked.

boolean r3 = a == sameA;  // This is true, since a and sameA are really the same object

==:对于基本类型比较值 ==:对于对象类型=保留/分配堆中的内存空间是相同的。 在这种情况下,a和sameA指的是同一个对象。

实施例。如果

 String x="singh";

    x+concat("Saheb");
//Here a new object is created  without having any reference to it with value "singhSaheb"

但是x保持不变。 String甚至Literal都被视为对象。