Literal string creation vs String object creation - java

How many String object are created
I am studying for the SCJP I cant seem to get my head round this String problem. I seem to see several possible answers depending on how i look at a question.
In the following initialization, how many string objects are created?
String s1 = "A" + "B" + "C" + "D";
System.out.println(s1)
Initially i thought 5 objects, i.e.
"A"
"B"
"C"
"D"
"ABCD"
But then thinking about it i am not really sure because for example will the compiler concatenate "A" + "B" as one object? i.e creating 7 objects?
"A"
"B"
"C"
"D"
"AB"
"ABC"
"ABCD"
Also, how many objects will be created if the code was changed to be
String s1 = new String("A" + "B" + "C" + "D");
System.out.println(s1);
And finally how about:
String s1 = "A";
String s2 = new String("A");
In the above example i think only 2 objects will be created
object 1 - "A"
object 2 - a String object that refers to the "A" object above.
Is this correct or will they not be related? i.e. the object referred to from the constant pool will be different from the one referred to by the s2 reference.
Thanks
Edit
Also, please note i am interested in knowing the total number of objects created including those that are discarded not just those that eventually end up in the constant pool.
Edit
Looking at Jon's answer i might have totally misunderstood the way the objects are created. I know that a String is created only once in the constant pool and it is reused but im not sure of the process that goes through when the 'final' string is constructed. Here is the section from the book i am reading which seems to suggest that temporary objects get created which is a complete opposite to the answers here. (Or maybe the book is wrong or i misunderstood the book)
The code sample was
String s1 = "spring ";
String s2 = s1 + "summer ";
s1.concat("fall ");
s2.concat(s1);
s1 += "winter";
System.out.println(s1 + " " + s2);
The question was
What is the output? For extra credit, how many String objects and how
many reference varibles were created prior to the println statement.
And the answer
The result of this code fragment is spring water spring summer. There
are two reference variables, s1 and s2. There were a total of eight
String objects created as follows "spring", "summer" (lost), "spring
summer", "falls"(lost), "spring fall" (lost), "spring summer spring"
(lost), "winter" (lost), "spring winter" (at this point "spring" is
lost). Only two of the eight String objects are not lost in this
process
Thanks

The compiler will concatenate the whole of "A" + "B" + "C" + "D" into a single constant - so in your first example, only a single string ends up created at all. That same string will be reused if you execute the same code multiple times. The constant is put in the class file, and when the class is loaded the VM checks whether an equal string is already in the string pool - so it will reuse it even if you have the same code in multiple classes.
You can verify that only a single string is in the constant pool within the class with javap:
javap -v Test
Constant pool:
#1 = Methodref #6.#17 // java/lang/Object."<init>":()V
#2 = String #18 // ABCD
#3 = Fieldref #19.#20 // java/lang/System.out:Ljava/io/PrintStream;
However, here:
String s1 = "A";
String s2 = new String("A");
you do end up with two separate string objects. One (the constant) will be reused every time you execute the code (and is shared between the two statements), and a new one will be created due to the constructor call each time.
So for example, this method:
public static void foo() {
for (int i = 0; i < 5; i++) {
String s1 = "A";
String s2 = new String("A");
}
}
... will end up using six string objects - one for the constant, and five new ones created each time you call the method.

How many objects created?
String s1 = "A" + "B" + "C" + "D";
System.out.println(s1)
One or none. This is reduced to one String literal which could be already loaded.
String s1 = new String("A" + "B" + "C" + "D");
System.out.println(s1);
This always creates an extra object.
BTW: A string usually consists of two objects, the String and the char[] it wraps.

String s1 = "A" + "B" + "C" + "D";
The compiler will create only one string literal "ABCD" and put it in the String pool. One object will be created (the one in the String Pool).
String s1 = new String("A" + "B" + "C" + "D");
Same here, except that you are copying it from the String literal. So, 2 object will be created here. One by the new and one in the String Pool.
String s1 = "A";
String s2 = new String("A");
Same here, "A" will be a constant in the string pool. The constructor will copy it. So here two objects will be created.

Related

What happens when a string literal is changed? [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
toUpperCase in Java does not work [duplicate]
(5 answers)
Closed 6 years ago.
I want to change a string literal into all-uppercase one. Here is my code:
// a and b are the same literal
String a = "Test";
String b = "Test";
// now I want to change all b's letter
// into uppercases, but fail.
b.toUpperCase();
System.out.println("a = " + a + ", " + "b = " + b);
// print: a = Test, b = Test
String c = "Test1";
System.out.println("c = " + c + " , c.toUpperCase() = "
+ c.toUpperCase());
// print: c = Test1 , c.toUpperCase() = TEST1
// change letters of "Test" literal
// into uppercase and success
System.out.println("Test".toUpperCase());
// print: TEST
My question is:
1. b can't be changed into uppercase one, but c and "Test" can. Why?
What I know is:
1. a and b reference to the same object in string pool.
2. String is immutable, but it seems not relevant to this question.
Strings are immutable. So for change b:
b = b.toUpperCase();
Every time then you do something that changes a String, a new String object is created. So you need change the reference on object.
String is immutable, but it seems not relevant to this question
Actually, it's very relevant to the question
b can't be changed into uppercase one
Because toUpperCase() returns a new string by acting on the invoking string , use
b = b.toUpperCase();
c and "Test" can. Why?
c has not been changed it's result has been added to the string in System.out.println()
Let's take your code line by line and please read my comments :
// a and b are the same literal
/* FIRST POINT :
Here you assigned two times the same value "Test",
BUT IT'S 2 DIFFERENT OBJECTS IN MEMORY */
String a = "Test";
String b = "Test";
// now I want to change all b's letter
// into uppercases, but fail.
/* SECOND POINT :
Here you just apply a function (toUpperCase()) on "b" object.
This function returns a string object but
YOU ARE NOT DOING ANYTHING WITH IT
i.e. displaying it or reassigning it to another variable!
*/
b.toUpperCase();
System.out.println("a = " + a + ", " + "b = " + b);
// THAT'S WHY IT STILLS PRINT
// print: a = Test, b = Test
String c = "Test1";
System.out.println("c = " + c + " , c.toUpperCase() = "
+ c.toUpperCase());
/* THIRD POINT :
Here you apply a function (toUpperCase()) on "c" object but this time
YOU ARE REUSING THE RETURN STRING :)
i.e. you are displaying it!
*/
// print: c = Test1 , c.toUpperCase() = TEST1
// change letters of "Test" literal
// into uppercase and success
/* LAST POINT :
Here you do the same as you did before on "c" object
YOU ARE REUSING THE RETURN STRING AGAIN :)
i.e. you are displaying it!
*/
System.out.println("Test".toUpperCase());
// print: TEST
Last but not least calling toUpperCase()/toLowerCase() functions on string objects will never reassign the object's value. These functions only RETURN a string.
The way to reassign the string value is the usual way :
String a = "Test";
a = a.toUpperCase();
Please note, as many said, that this will create another object in memory "TEST" and assign it to "a" and your old string "Test" will then become a candidate to the garbage collector.
I hope it makes more sense now.
Cheers,
What happens when a string literal is changed?
Nothing. That is the string literal object cannot change, because as you point out you already know, it is immutable. References to it (variables like a,b,c) can be made to reference other strings, but that string instance will not change from "Test".
But to explain your code:
This is the difference between b and c:
b.toUpperCase(); //there's a result from this function you are not using
System.out.println("b = " + b);
System.out.println("c = " + c.toUpperCase()); //you're using the result here.
String is immutable, but it seems not relevant to this question
It is relevant, if you know that it is immutable, it is obvious that b cannot change to upper case and that a new string must be created as a result of toUpperCase and you must therefore use that. However b can be made to reference the new string, and this wont affect a or anything else which still references the old string:
b = b.toUpperCase(); //b now is set to the new upper case string
System.out.println("b = " + b);
My question is: 1. b can't be changed into uppercase one, but c and "Test" can. Why?
My answer is when you print c.toUpperCase(), variable c is not changed at all.
You merely returned the another String which was built to uppercase based on the content of c.
The same applies to String "test" as well.
Even if you do this, you are only pointing c to a new String:
String c = "Test1";
c = c.toUpperCase();
This is what happened:
//String c = "Test1";
+-------+
|"Test1"| <--- c
+-------+
//c = c.toUpperCase();
+-------+
|"TEST1"| <--- c
+-------+
+-------+
|"Test1"| <--- waiting to be collected by Garbage collector
+-------+
You need to change like this,because strings are immutable
public static void main(String[] args) {
// a and b are the same literal
String a = "Test";
String b = "Test";
// now I want to change all b's letter
// into uppercases, but fail.
b= b.toUpperCase();
System.out.println("a = " + a + ", " + "b = " + b);
// print: a = Test, b = Test
String c = "Test1";
// c=c.toUpperCase();
System.out.println("c = " + c + " , c.toUpperCase() = "
+ (c=c.toUpperCase()));
// print: c = Test1 , c.toUpperCase() = TEST1
// change letters of "Test" literal
// into uppercase and success
System.out.println("Test".toUpperCase());
// print: TEST
I suggest you to look into the Java API. By using toUpperCase you will get a new Object of String. If you want to print out the variable with new text, you should assign the new object to the variable. In case of c, you're printing out the returned "new" content of the object. The variable c will be lower case anymore.

String intern for GC

I have read many artiles regarding string interning.
If I create a String object
Method 1
String str= new String("test")
2 Objects are created one in heap and other in string pool.
Method 2 if method 1 is not executed
String str= new String("test").intern()
it will create a copy of string frpoom heap to string pool .How many objects will be created.I guess 3.One will be in heap ,other in pool and one "test" literal.
Which one will be eligible for GC in both cases.I have seen artilces that say 2 are getting created but i am unable to understand why?
Method 3
String s= new String("test")
String s1=s.intern()
It does the same thing except the s point to heap object and s1 to pool object and none of them are eligible for Gc.
Is my understanding correct???I am confused a lot on this concept.
If I create a String object
String str= new String("test")
Objects are created one in heap and other in string pool.
A String consists of two objects, the String and the char[] In some version of Java it could be a byte[] Or in fact a char[] which is later replaced by a byte[]. This means that 4, perhaps 5 objects could be created, unless the String for the string literal already exists, in which cases it is 2 for Java 7 update 4+, before that the char[] would be shared so it could be three objects or only 1.
String str= new String("test").intern()
This is exactly the same except, if this is called enough the new String could be allocated on the stack and you might find that only the char[]` is created and this cannot be placed on the stack, at the moment. In future this might be optimised away also.
Which one will be eligible for GC in both cases.I have seen artilces that say 2 are getting created but i am unable to understand why?
The answer is anywhere from 1 to 4 depending on the situation. All of there eligible for collection unless they are being strongly referenced somewhere.
String intern() method:
The most common methods for String comparison are the equals() and equalsIgnoreCase() methods. However, these methods may need large amount of memory for large sequence of characters. The Java String intern() method helps us to improve the performance of the comparison between two Strings.
The intern() method, when applied to a String object, returns a reference to this object (from the hash set of Strings that Java makes), that has the same contents as the original object. Thus, if a code uses the intern() method for several String objects, then our program will use significantly less memory , because it will reuse the references of the objects in the comparison between these Strings.
Keep in mind, that Java automatically interns String literals. This means that the intern() method is to be used on Strings that are constructed with new String().
Example:
JavaStringIntern.java
package com.javacodegeeks.javabasics.string;
public class JavaStringIntern {
public static void main(String[] args) {
String str1 = "JavaCodeGeeks";
String str2 = "JavaCodeGeeks";
String str3 = "JavaCodeGeeks".intern();
String str4 = new String("JavaCodeGeeks");
String str5 = new String("JavaCodeGeeks").intern();
System.out.println("Are str1 and str2 the same: " + (str1 == str2));
System.out.println("Are str1 and str3 the same: " + (str1 == str3));
System.out.println("Are str1 and str4 the same: " + (str1 == str4)); //this should be "false" because str4 is not interned
System.out.println("Are str1 and str4.intern() the same: " + (str1 == str4.intern())); //this should be "true" now
System.out.println("Are str1 and str5 the same: " + (str1 == str5));
}
}
Output:
Are str1 and str2 the same: true
Are str1 and str3 the same: true
Are str1 and str4 the same: false
Are str1 and str4.intern() the same: true
Are str1 and str5 the same: true
Points to note is
Interning is automatic for String literals, the intern() method is to be used on Strings constructed with new String()
The Strings (more specifically, string objects) will be garbage collected if they ever become unreachable, like any other java objects.
String literals typically are not candidates for garbage collection. There will be a implicit reference from the Object to that literal.
Reason for point#3 is If a literal is being used inside a method to build a String is reachable for as long as the method could be executed.

Is a valid scenario for assigning string from string pool?

I have been given the following condition?
String A="a";
String B="b";
String c="a"+"b";
My question is is the String c created newly or is assigned from the string pool the value "a" and "b" and total how many strings are formed according to above question?
Yes c is created newly. Strings in Java are effectively immutable (i.e. once created, they never change). One of the consequences of this is that, whenever you do a manipulation that changes a string, you get back a new, different object.
So in your example, 3 strings are created.
Take these two String objects:
String a = "a";
String b = "b";
String c = "a" + "b";
String d = "ab";
The compiler creates and pools three String objects. A line by line explanation follows.
Line 1: One String object is pooled for "a"
Line 2: One String object is pooled for "b"
Line 3: "a" + "b" is computer at compile time and treated as a literal. Therefore, one String object is pooled for "ab"
Line 4: "ab" is already in the pool
Following the same guidelines, your example produces 3 String objects.

What's the difference between String s = "something"; and String s = new String("something"); [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
difference between string object and string literal
When initializing a String object there are at least two ways, like such:
String s = "some string";
String s = new String("some string");
What's the difference?
The Java language has special handling for strings; a string literal automatically becomes a String object.
So in the first case, you're initializing the reference s to that String object.
In the second case, you're creating a new String object, passing in a reference to the original String object as a constructor parameter. In other words, you're creating a copy. The reference s is then initialized to refer to that copy.
In first case you can take this string from pool if it exist there.
In second case you explicitly create new string object.
You can check this by these lines:
String s1 = "blahblah";
String s2 = "blahblah";
String s3 = new String("blahblah");
String s4 = s3.intern();
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s3);
System.out.println(s1 == s4);
Output:
true
false
false
true
String s = "some string"; assigns that value to s from string pool (perm.gen.space) (creates one if it does not exist)
String s = new String("some string"); creates a new string with value given in constructor, memory allocated in heap
The first method is recommended as it will help to reuse the literal from string pool
Semantically, the first one assigns "some string" to s, while the second one assigns a copy of "some string" to s (since "some string" is already a String). I see no practical reasons to do this in 99.9% of cases, thus I would say that in most contexts, the only difference between the two lines is that:
The second line is longer.
The second line might consume more memory than the first one.
As #Anish-Dasappan mentions, the second one will have it's value in heap, whereas the first one will be in the string pool - I'm not sure this has any interest for the programmer, but I might be missing a clever trick there.

Java String variable setting - reference or value?

The following Java code segment is from an AP Computer Science practice exam.
String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);
The output of this code is "abc ab" on BlueJ. However, one of the possible answer choices is "abc abc". The answer can be either depending on whether Java sets String reference like primitive types (by value) or like Objects (by reference).
To further illustrate this, let's look at an example with primitive types:
int s1 = 1;
int s2 = s1; // copies value, not reference
s1 = 42;
System.out.println(s1 + " " + s2); // prints "1 42"
But, say we had BankAccount objects that hold balances.
BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1.setBalance(0);
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 0"
I'm not sure which is the case with Strings. They are technically Objects, but my compiler seems to treat them like primitive types when setting variables to each other.
If Java passes String variables like primitive type, the answer is "abc ab". However, if Java treats String variables like references to any other Object, the answer would be "abc abc"
Which do you think is the correct answer?
java Strings are immutable, so your reassignment actually causes your variable to point to a new instance of String rather than changing the value of the String.
String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);
on line 2, s1 == s2 AND s1.equals(s2). After your concatenation on line 3, s1 now references a different instance with the immutable value of "abc", so neither s1==s2 nor s1.equals(s2).
The difference between your BankAccount and a String is that a String is immutable. There is no such thing as 'setValue()' or 'setContent()'. The equivalent example with your bank account would be :
BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1 = new BankAccount(0);
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 500"
So if you think of it this way (not actually what the compiler does, but functionally equivalent) the String concatenation scenario is:
String s1 = "ab";
String s2 = s1;
s1 = new String("abc");
System.out.println(s1 + " " + s2); //prints "abc ab"
It is not relevant whether String is treated like a primitive or like an object!
In the String example, the concatenation of two strings produces a new String instance, which is then assigned to s1. The variable s2 still references the unchanged(!) old String instance.
Assuming the BankAccount had a method to set the balance, which returns a new BankAccount, your example could look like this:
BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1 = b1.createNewAccountWithBalance(0); // create and reference a new object
System.out.println(b1.getBalance() + " " + b2.getBalance()); // prints "0 500"
Indeed, String is a class and it's assigned / passed by reference.
But what's confusing is the statement:
String s = "abc";
Which suggests that String is a primitve ( like 'int x = 10;' );
But that's only a shortcut, the statement 'String s = "abc";' is actually compiled as 'String s = new String( "abc" );'
Just like 'Integer x = 10;' is compiled as 'Integer x = new Integer( 10 );'
This mechanism is called 'boxing'.
And more confusing is: there's a class 'Integer' and a primitive 'int',
but String doesn't have a primitive equivalent (allthough char[] comes close)
Sije de Haan
In Java, String objects are assigned and passed around by reference; it this respect they behave exactly like any other object.
However, Strings are immutable: there isn't an operation that modifies the value of an existing string in place, without creating a new object. For example, this means that s1 = s1 + "c" creates a new object and replaces the reference stored in s1 with a reference to this new object.
String is a class, so a String variable is a reference. But it's a language intrinsic, in the sense that Java has special handling and syntax for it, which is why you can do things like your example.
See e.g. http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html.
java.lang.String is an object, not a primitive.
What the code did in the first example is:
Define s1 as "ab"
Set s2 equal to the same underlying object as s1
Set s1 equal to a new string that is the combination of s1's old value and "c"
But to answer your question about reference or value, it's by reference.
The assertion
if Java treats String variables like references to any other Object, the answer would be "abc abc"
is incorrect. Java does treat String variables like references to any other Object. Strings are Objects but the answer is "abc ab" none the less.
The issue is not what the assignment operator does. The assignment operator assigns a reference to a String object in every case in your example.
The issue is what the concatenation operator ('+') does. It creates a new String object. As other have said, this is necessary because a String object is immutable but it is an issue of operator behaviour and not merely because String is immutable. The concatenation operator could return a new Object even if a String object were mutable.
In contrast, in your second example, b1.setBalance(0) does not create a new object, it modifies the existing object.
int s1 = 1;
int s2 = s1; // copies value, not reference
s1 = 42;
System.out.println(s1 + " " + s2); // prints "1 42"
Doesn't print "1 42" but "42 1".Take each discrete line into consideration.First s1 assigns 1, then s2 assigns s1, which is 1 up until now(suppose java didn't see the third line yet.) Then java sees the third line and immediately changes s1 into 42.After that java was told to print what it knows so far, and that is s1 is 42 and s2 is 1(the old s1).
As for the String the same thing happens.
String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);// prints "abc ab".
Fort String it doesn't necessarily changes s1 but rather s1 now refers to a new String object in the heap memory, but the old "ab" object is still there, with a new reference of s2!

Categories