user3155653
user3155653

Reputation: 11

Immutable Types in Java vs. Python

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

Why is this the case? Because strings are immutable, don't a and b point to the same string? For example, if I do the same thing in Python, this is what I get:

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

I'm assuming that Java's == is the same as Python's 'is', and Java's .equals is the same as Python's ==, in which case the two blocks of code contradict each other.

I also have a suspicion that this might have to do w/ the fact that Java doesn't treat Strings as primitives?

Upvotes: 1

Views: 504

Answers (3)

abarnert
abarnert

Reputation: 365925

Because strings are immutable, don't a and b point to the same string?

No. In Java, they don't because you're explicitly asking it to create a new String object out of the literal, and then to create another new String out of the same literal, which guarantees that you get two different objects. (And in your Python test, you get the exact same results, although that isn't guaranteed by the language—see below for details.)


I'm assuming that Java's == is the same as Python's 'is', and Java's .equals is the same as Python's ==

Close enough to true for this question.

in which case the two blocks of code contradict each other.

No they don't. You translated two tests to Python, and got the exact same results as in the two corresponding Java tests. You didn't translate the third test at all, so there's nothing there to contradict with anything.

Let's repeat your 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

… and translate it more closely to 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

The [:] are there to match the new in the original code. You're explicitly asking Java to create a new String object out of the literal "Wow". In Python, there's no way to explicitly ask for a new object, but you can always ask for a copy, which is close enough (as long as you don't care about the fact that you might be creating a couple extra strings as garbage to be immediately collection).


However, if you remove the [:], you're often going to get the same results anyway—as you saw in your own tests. You got True for a == b and False for a is b too. Repeating the tests that way:

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

In your comment, you say that a is b was actually True, not False.

As explained above, that's also perfectly legal. While Java requires that new String create a new String object, nothing in Python requires that evaluating the same string literal twice has to create two separate string objects, or even that copying a string object has to create a new string object. See below for more.


I also have a suspicion that this might have to do w/ the fact that Java doesn't treat Strings as primitives?

Indirectly, it's sort of to do with the fact that Java doesn't treat Strings as primitives, and also to do with the fact that Python doesn't treat string literals the same way as some other kinds of literals.

In Java, because String is not a primitive, you have a choice to explicitly create a new String. And you do that. So, it's not going to be the same as any previous instance. The fact that they're both immutable instances is irrelevant; Java is not allowed to collapse separate objects into a single object if there's any way that it would be visible.

In Python, "Wow" is a literal, and you're not asking it to create a new string. And strings are immutable, and Python is allowed to collapse separate immutable built-in objects in ways that Java is not. So it can combine the two literals into one. Even with the [:], it's allowed to collapse the new copy into the original. And with small integers, it will generally do so—try the same test with 0 (use copy.copy(0) to test explicit copying) rather than "Wow" and see what happens. But the major Python implementations often happen to not do this for strings, so you end up with separate objects, so you can get the same result as in Java.


What this means in practice is that, with code like yours, either with or without the explicit copy, a is b and a is not b are both perfectly legal and reasonable things to happen, so your code should never rely on either one being true. Fortunately, there's very little reason to do so. (If you were thinking performance might be a good reason, try calling timeit on a is b vs. a == b, and you'll find something like 55.3ns vs. 61.0ns.)


One last thing to keep in mind: Python and Java are very different languages, so it shouldn't be all that surprising that similar-looking code sometimes acts very differently (or that very different-looking code sometimes acts similarly). The fact that English rules for when to use this vs. that are not the same as Japanese rules for kore vs. sore vs. are is not surprising, it's just something you have to learn when you learn Japanese (or when you learn English).

Upvotes: 4

Sunny Rathor
Sunny Rathor

Reputation: 13

Immutability:Object Not subject to change.

to your question

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

Reference variables a and b are not referring to same Object.When String is created with new operator a totally new memory space is Reserved in Heap for the same string Literal.

If String Pool is not having the facility of making string immutable in that case string pool with one string object/literal has referenced by many reference variables and if any one of them changes the value others will be automatically gets changed. For example

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

Now String secondString called "xyzabc".toUpperCase() which change the same object into "XYZABC" , so A will also be "XYZABC" which is not desirable.

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

== :for Basic types compare the values == :for Object type =Reserved/Allocated Memory Space in the Heap is same. in this case a and sameA referring to the same object.

Ex. If

 String x="singh";

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

But x remain same. String and even Literal are treated as object.

Upvotes: 0

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136062

In Java new operator always returns a new object which occupies its own place in memory and has a unique pointer.

Upvotes: 0

Related Questions