a confusion about java String literal pool and String's concatenation - java

all,
i faced a problem when a write the code below
String hello = "Hello";
String str5 = "Hel" + "lo";
String str8 = "Hel";
String str9 = "lo";
String str10 = str8 + str9;
System.out.println("str10==hello?" + (str10 == hello));
System.out.println("str5==hello?" + (str5 == hello));
System.out.println("str10==str5?" + (str10 == str5));
then i run my code and the console print this
str10 == hello ? false
str5 == hello ? true
str10 == str5 ? false
this confused me a lot. why the second print TRUE but the first print FALSE??
in my comprehension of String literal pool,when a string defined and JVM will check if the pool contains that string,if not ,put the string into the pool.in my code,variable hello exists in string pool,"Helo" and "lo" also in the pool,my question is
if the result of the concatenation of "Helo" and "lo" exists in the pool.
what's the difference between the definition about str5 and str10s',and why they are not "=="? does str5 and str10 refer to the diffrent "Hello” that in the string pool?("==" seems to mean the reference is the same object)
my jdk version :1.6.0_29
my IDE:Intellij Idea 11.2
anyone can point it out? thank you very much

It behaves as it should. It is adressed in two sections of the JLS.
JLS #3.10.5:
strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
JLS #15.28 lists what is considered as a constant expression. In particular, string literals are constant expressions ("Hel" and "lo") but for a variable to be considered a constant, it needs to be final.
In your case, if you change your code slightly to make str8 and str9 constant, you will get true three times:
final String str8 = "Hel";
final String str9 = "lo";

String hello = "Hello"; // at compile time string is known so in String Constant Pool
String str5 = "Hel" + "lo"; // at compile time string is known so in String Constant Pool same object as in variable hello
String str8 = "Hel"; // at compile time string is known so in String Constant Pool
String str9 = "lo"; // at compile time string is known so in String Constant Pool
String str10 = str8 + str9; // at runtime don't know values of str8 and str9 so in String Constant Pool new object different from variable hello
str10 == hello ? false // as str10 has new object and not the same as in hello
str5 == hello ? true // both were created at compile time so compiler know what's the result in str5 and referenced the same object to str5 as in hello
str10 == str5 ? false // str10 is a different object, hello and str5 are referenced same object as created at compile time.

The code has the following points to consider:
String hello = "Hello";
Here "Hello" is a literal assigned to reference hello thus the literal has its own hashcode
String str5 = "Hel" + "lo";
Here "Hel"+"lo" are 2 literals combined and assigned to reference hello thus the new literal is same as the first one and thus same hashcode
String str8 = "Hel";
String str9 = "lo";
Here str8 + str9 are 2 references which combine and point to a new reference hello thus the new literal has its own hashcode
String str10 = str8 + str9;
System.out.println("str10==hello?" + (str10 == hello));
System.out.println("str5==hello?" + (str5 == hello));
System.out.println("str10==str5?" + (str10 == str5));
when you use == it matches by hash code and value. thus the mismatch.
try to use
string_1.equals(string_2)
instead of
string_1 ==string_2
and you will get value matching only. thus all true
Please refer the below answer also(from What is the difference between == vs equals() in Java?):
The equals() method compares the "value" inside String instances (on the heap) irrespective if the two(2) object references refer to the same String instance or not. If any two(2) object references of type String refer to the same String instance then great! If the two(2) object references refer to two(2) different String instances .. it doesn't make a difference. Its the "value" (that is: the contents of the character array) inside each String instance that is being compared.
On the other hand, the "==" operator compares the value of two object references to see whether they refer to the same String instance. If the value of both object references "refer to" the same String instance then the result of the boolean expression would be "true"..duh. If, on the other hand, the value of both object references "refer to" different String instances (even though both String instances have identical "values", that is, the contents of the character arrays of each String instance are the same) the result of the boolean expression would be "false".

If u compare two strings use string.equals not string1 == string2
try it:
System.out.println("str10==hello?" + (str10.equals(hello));

Related

Does Java string pool store duplicate literals?

As I have understood, whenever we create a String literal, the pool is checked for any existing String with the same value. If it exists, a reference to the same is returned. Otherwise a new literal is created.
From this, I understand that pool only contains non-duplicate String literals.
But I am confused by the output of the following code:
String str1 = "Hello World";
String str2 = "Hello";
String str3 = str2+" World";
System.out.println(str3);
System.out.println(((str1 == str3) ? "equal":"unequal"));`
Since str3 is evaluating to "Hello World" which already exists in the pool pointed to by str1, a reference to the same should be assigned to str3 and hence str1 and str3 should be equal.
But the code is showing them as unequal.
Would appreciate if someone can explain.
str2 + " World" is not a constant expression, so it is not interned. If str2 were final or it were directly written as "Hello" + " World", then the value would be interned.
§3.10.5. String Literals:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
See also: §15.28. Constant Expressions
When you concatenate the strings, you're creating a new string which is different from the one in the pool.
If you call the method intern() then you'll get the expected behavior.
jshell> var a = "hello"
a ==> "hello"
jshell> var b = " world"
b ==> " world"
jshell> a + b == "hello world"
$3 ==> false
jshell> (a + b).intern() == "hello world"
$4 ==> true
I agree with #Unmitigated
When you are writing
String str3 = str2+" World";
You are in fact creating a string that cannot be known before runtime (or maybe with compiler optimisations, but that's not the point). So the string is considered to be unique
That's the reason why each string should be compared with equals method and never with "=="
As I have understood, whenever we create a String literal, the pool is checked for any existing String with the same value.
The key word is "literal".
String str2 = "Hello";
String str3 = str2+" World";
"Hello" is a string literal.
" World" is a string literal.
str2 + " World" is an expression that concatenates two string values.
A "literal" literally appears as itself in the source code.
It would not be an optimization if the result of every string operation needed to check the literal pool to see if that string had ever appeared before. The overhead is acceptable at compile time, since that's a one-time cost.

How new String() and normal String created ? String class in java (Confusion) [duplicate]

This question already has answers here:
Strange behavior with string interning in Java
(4 answers)
Closed 5 years ago.
I was reading about String in java and was trying to understand it.
At first, it was easy how String s1="11" and String s2=new String ("11") works(created) and I understood intern method also.
But I came across this example (Given by a friend) and made me confused about everything.
I need help to understand this.
String s1 = new String(new String("2")+new String("2"));
s1.intern();
String s2="22";
System.out.print(s1==s2); //=>true as output.
String s3 =new String (new String("2")+new String("2"));
s3.intern();
String s4="22";
System.out.print(s3==s4); //=>false as output.
Answer of this code is true and false.
Part for S1 and s2 was good and was true according to my understanding but the second part I didn't understand.
Hope someone can break the code line by line and help me understand.
s1.intern(); adds s1 to the pool of strings, therefore the string "22" is now in the pool of strings. Therefore when you write s2 = "22" that's the same "22" as s1 and thus s1 == s2.
s3.intern() does NOT add s3 to the pool of strings because the string "22" is already there.
s3.intern() does return that same "22" which is s1 BUT IT IS NOT USED. Therefore s3 is not equal s4.
In java exist the heap and the stack,
Heap is where all Objects are saved
stack is where vars are saved
Now also exist another kind of list for Strings and Integers (numbers)
As you know a String can be created in some ways like
like new String("word") or just = "word" when you use the first way you create a new object (heap) when you use the other you save the word in a stack of words (Java engenniers thought it would be good if you don't create manny objects or words are repeated so they created an special stack for words, same for Integers from 0 to 127) So as I said You have to know that there is an stack and a Heap look at this example
String wordOne ="hola";
String wordTwo = "hola";
String wordTres = "hola";
System.out.println(wordOne == wordTwo);
System.out.println(wordTres == wordTwo);
System.out.println(wordOne == wordTres);
String wordFour = new String("hola");
System.out.println(wordOne == wordFour);
Integer uno = 127;
Integer dos = 127;
System.out.println(uno == uno);
Integer tres = 128;
Integer cuatro = 128;
System.out.println(tres == cuatro);
String x = "word"; is saved in an special Stack
String y = new String("it is not");
But tbh I don't remeber so well the rules for tha stack, but in any case i recomend you to compare all words using wordX.equals(wordY)
An also numbers in objects could be compared using == from 0 to 127 but the same if you use objects use equals, although using numbers there is a better do to do it in spite of use equals, convert one number to a primitive value (the memory will be better)
When you are making string with new keyword,JVM will create a new string object in normal(non pool) heap memory and the literal will be placed in the string constant pool. In your case, The variable s1 will refer to the object in heap(non pool).
String s1 = new String(new String("2")+new String("2"));
But in the next line your are calling intern() method.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
Check Javadocs.
As "22" is not in string pool, a new string literal "22" will be created and a reference of it will be returned. When you are writing:
String s2="22";
it simply refers "22" in string pool. But calling s3.intern() will not create a new string literal as "22" exists in the pool. Check the Javadocs for intern() again. It says if exists in pool, then string from the pool is returned not reference. So, this time s3 references to a different object.
But s4 is referred to same object as s1,s2.
You can print the objects hashcode for checking if the are same or not. Like:
System.out.println(System.identityHashCode(s1));
Notice that the type String is capitalized and is not one of Java's 8 primitive types (int, boolean, double, char, etc.). This indicates that any instance of a String is an object that was built using the 'blueprint' of the class String. Because variables in Java that refer to objects only store the memory address where the actual object is stored, when you compare Strings with == it compares memory location.
String str1 = new String("hello");
String str2 = str1; //sets str1 and str2 pointing to same memory loc
if (str1 == str2){
//do stuff; the code will enter this if-statement in this case
}
The way to compare the values within objects in Java is with equals(), such as:
String str1 = new String("hello");
String str2 = new String("hello"); //str2 not same memory loc as str1
if (str1.equals(str2)){
//do stuff; the code will enter this if-statement in this case
}
This is a common error for beginners, since the primitive types are not objects and you CAN compare two ints for equality like:
int one = 1; //primitive types are NOT objects
int two = 2; //notice when I make an int, I don't have to say "new"
//which means a new **object**
if (int1 == int2) {
//do stuff; in this case the program will not enter this if-statement
}
It seems that you understand everything but the meaning of the very last line. See my comment on the last line.
String s1 = new String(new String("2")+new String("2")); //declare AND initialize s1 as a new String object
s1.intern();
String s2="22"; //declare a new variable s2 and point it to the same object that s1 is pointing to
System.out.print(s1==s2);
String s3 =new String (new String("2")+new String("2"));
s3.intern();
String s4="22";
System.out.print(s3==s4); //check if s3 and s4 are stored in the same memory location = FALSE
In java object1 == object2 means
that do object1 and object2 have the same address in memory?
object1.equals(object2)
means are they equal, for example do they have the same values of all fields?
So, For two Strings S1 and S2,
string1.equals(S2) means, do they have the same characters in the same sequence?
S1 == S1 means are string1 and string2 stored at the same address in memory?

java String comparison in concat

package data;
public class A {
String s = "maew";
String s2 = s + "class";
String s1 = "maewclass";
System.out.println(s2 == s1);
}
}
but both will be in string constant pool and if with same content an object is created one more reference will not get created. s2 and s1 should point to same object in string constant pool.so answer should be true why its giving false
String constant pool is an internal java feature which you should never rely on. For instance the following code will produce "true"
String s1 = "Hello";
String s2 = "Hello";
boolean result = s1 == s2;
But the following code will produce "false":
String s1 = "Hello";
String s2 = new String("Hello");
boolean result = s1 == s2;
String constant pool behavior may change from one java version to another since it is an internal optimization feature. It shouldn't be relied on. In your case, I suspect because you used String s2 = s + "class"; it did create a new instance.
In any case any String comparison MUST be done with method equals() of class String
I haven't look at the documentation, just did my own testing and what i believe that the reason you are getting "false" is because your S2 was a result of concatenation of an object (s) and the other string.
If you run this code
// String s = "maew";
String s2 = "maew" + "class";
String s1 = "maewclass";
System.out.println(s2 == s1);
The it is indeed returning true. So I believe, that java is not keeping result of Object.toString + "string" in the stringpool.
String grima = "grima";
String gri = "grima";
if (grima == gri)
System.out.println("grima == gri"); // The message is displayed
Both variables refer to same "grima" in string constant pool.
String pndey = "pandey";
String pan = "pande";
pan = pan + "y"; // The value for pan will be resolved during runtime.
if (pndey == pan)
System.out.println("pndey == pan"); // The 2 references are different
Now in the second case if I change
pan = pan + "y"; to pan="pande" +"y", then "pndey == pan" message will be displayed, because the compiler resolves the literal during compilation time.
Now as per Java docs on string:
Literal strings within the same class (§8 (Classes)) in the same package (§7 (Packages)) represent references to the same String object (§4.3.1).
Literal strings within different classes in the same package represent references to the same String object.
Literal strings within different classes in different packages likewise represent references to the same String object.
Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
Strings computed by concatenation at run time are newly created and therefore distinct.
The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.
You read more here: https://codingninjaonline.com/2017/09/18/stringstring-constant-pool-in-java/
you need to use s2.equals(s1) instead of == please go through link provided for more
here
Update :
When we create object its reference is placed in the string constant pool memory.
So in your case when program is run...
JVM finds the variable s2 which refers to s + "class" in which s is also referencing maew and will be placed in the string constant pool memory.Then it finds another variable s1 which is referring maewclass.
JVM finds two different string references so both the variables s2 and s1 will not be refer for same string (say..maewclass).
At point when class is loaded if two same values are passed it is will refer to previous object rather creating the new one...
String objects with same values will always refer to the same String object.
String s = "a";
String s2 = "a";
System.out.println(s.equals(s2)); //-------return true
System.out.println(s == s2); //-------return true
_____
s ------------------> | |
| "a" |
s2 ------------------> |_____|
^
|
___________|____________
| Heap |
| String Constant Pool |
|______________________|
String objects created using new operator will be different from literals
String s = "a";
String s2 = new String("a");
System.out.println(s.equals(s2)); //-------return true
System.out.println(s == s2); //-------return false

Class Hello in a test

I have come across this question in a test:
class Hello {
public static void main(String[] args){
String hello = "Hello", lo = "lo";
System.out.println(hello == ("Hel" + "lo"));
System.out.println(hello == ("Hel" + lo));
System.out.println(hello == ("Hel" + lo).intern());
}
}
The output is:
true
false
true
Why is the second output false?
It prints 'false' because the concatenation of the String constant "Hel" and the String object 'lo' results in a seaparate, anonymous string object, with its own unique object reference. Thus, the "hello" String object and the concatenated string are different objects based on object reference (== operator, not by String value with String.equals()).
== compares the references of two sides.
Here, for hello == ("Hel"+lo), the references of two sides are not the same. So, it returns false.
For comparing values, use equals() method.
I think it Comparision Literal Problem.
It Works.
System.out.print((hello.equals("Hel"+lo)) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
I think it is because in the second output ("Hel" + lo) is no more in the string. The equality "==" operator compares object memory location and not characters of String.By default Java puts all string literal into string pool, but you can also put any string into pool by calling intern() method of java.lang.String class, like string created using new() operator.

Behavior of String literals is confusing

The behavior of String literals is very confusing in the code below.
I can understand line 1, line 2, and line 3 are true, but why is line 4 false?
When I print the hashcode of both they are the same.
class Hello
{
public static void main(String[] args)
{
String hello = "Hello", lo = "lo";
System.out.print((Other1.hello == hello) + " "); //line 1
System.out.print((Other1.hello == "Hello") + " "); //line 2
System.out.print((hello == ("Hel"+"lo")) + " "); //line 3
System.out.print((hello == ("Hel"+lo)) + " "); //line 4
System.out.println(hello == ("Hel"+lo).intern()); //line 5
System.out.println(("Hel"+lo).hashCode()); //hashcode is 69609650 (machine depedent)
System.out.println("Hello".hashCode()); //hashcode is same WHY ??.
}
}
class Other1 { static String hello = "Hello"; }
I know that == checks for reference equality and check in the pool for literals. I know equals() is the right way. I want to understand the concept.
I already checked this question, but it doesn't explain clearly.
I would appreciate a complete explanation.
Every compile-time constant expression that is of type String will be put into the String pool.
Essentially that means: if the compiler can (easily) "calculate" the value of the String without running the program, then it will be put into the pool (the rules are slightly more complicated than that and have a few corner cases, see the link above for all the details).
That's true for all the Strings in lines 1-3.
"Hel"+lo is not a compile-time constant expression, because lo is a non-constant variable.
The hash codes are the same, because the hashCode of a String depends only on its content. That's required by the contract of equals() and hashCode().
Strings computed by concatenation at runtime are newly created and therefore distinct
here is a link to read: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
String object can be created in the following ways:
String str = new String("abcd"); // Using the new operator
// str is assigned with "abcd" value at compile time.
String str="abcd"; // Using string literal
// str is assigned with "abcd" value at compile time.
String str="ab" + "cd"; // Using string constant expression.
// str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1; // Using string expression.
// str is assigned with "abcd" value at run time only.
and Hashcode will be calculated only at runtime based on the contents of the String objects.
It's because the comipler in this instance is not smart enough to work out that it can burn in the same string literal.
Hashcode needs to always return the same value for strings that are equivelent (calling .equals on it returns true) so will return the same result.
Its because following code
("Hel"+lo)) + " "
is translated internally to
new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()
So you can see that entirely a new String instance is created with help of different String instances. That is why you get false as they point to different memory locations in heap
The hashCode doesn't have anything to do with an objects reference (The == check is a reference comparator). Its possible to have 2 objects where the hashCode returns the same value, the equals operator returns true, but == returns false. This is when they are 2 different objects, but with the same value.
I believe the reason line 4 is returning false is that it is a value computed at runtime, and thus is a different string instance, with a different reference.
String literals are saved in a special memory, if they are exactly the same, they are pointed to the same map of memory. If you don't create a literal String, a new object will be created so it won't point to that memory so the reference won't be the same.
The intern() method tells the virtual machine to put it into that shared, string literals map of memory so next time you do that literal, it'll search there and point it.
As you already know ... this is just because of reference ...when string comes from the pool it will have same refrence ...but when u do manuplations a new string with new refrence is generated ...
You can check this link for pooling concept
The difference between line number 3 and 4 are as follows.
•Strings computed by constant expressions are computed at compile time and then treated as if they were literals.
•Strings computed by concatenation at run time are newly created and therefore distinct.
The above reference is taken from java spec. Please let me know if you need more clarification.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
System.identityHashCode() would be returned by the default method hashCode(), this is typically implemented by converting the internal address of the object into an integer.
Finally I know the answer !
Read Java SE 8 specification section 15.21.3 Reference Equality Operators == and != (http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3)
While == may be used to compare references of type String, such an
equality test determines whether or not the two operands refer to the
same String object.
The result is false if the operands are distinct
String objects, even if they contain the same sequence of characters(§3.10.5). The contents of two strings s and t can be tested for
equality by the method invocation s.equals(t).
So the following code :
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
The expression ("Hel"+lo) in line 3, return the new Strings that computed by concatenation at run time.
*Strings computed by concatenation at run time are newly created and therefore distinct.
(http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634)
So the result of this code:
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
would result:
false
Because,
the "Hello" object in this expression:
String hello = "Hello";
and ("Hel"+lo) object in this expression:
System.out.print((hello == ("Hel"+lo)) + " ");
is different, although :
*they both contain the same sequence character, which is "Hello".
*they both have the same hashCode.
*hello.equals(("Hel"+lo)) will return true.

Categories

Resources