relationship between pool and heap - java

See the code.
String xx=new String("hello world");
String yy="hello world";
System.out.println("xx: " + xx);
System.out.println("yy: " + yy);
System.out.println("xx==yy:"+(xx==yy)); // false
//modify the value of yy using reflection
Field yyfield=String.class.getDeclaredField("value");
yyfield.setAccessible(true);
char[] value=(char[])yyfield.get(yy); // change the value of yy
value[5]='_';
System.out.println("xx: " + xx); // xx's value also changed.why?
System.out.println("yy: " + yy);
System.out.println("xx==yy:"+(xx==yy)); //false
I've seen some posts about Literal Pool, know xx and yy point to different place. But why I change the value of yy, xx also changed. Is there any operation in reflection or some other aspects I don't know? Thanks in advance.

xx and yy are two distinct String instances but they refer to the same internal char[] array.
This is an implementation-specific detail and changed between the Java versions. In the past, the constructor String(String) offered a way to create a String with a new char[] array for the case that the source String is a sub-string of a much larger string. However, current implementations allocate a smaller array and copy contents in the subString operation already, eliminating the need for copying in the constructor, hence the constructor String(String) simply uses the same array reference.
Even more fancy, the most recent (Java 8) JVMs have a String de-duplication feature whereas the garbage collector will change the array references to point to the same array once it found out that two String instances have the same contents. So it can collect one of the two arrays while maintaining the same semantics.

The instance field value is the same instance for both xx and yy. This value also corresponds to the literal that's interned in the string pool.

Related

Does string pool store literals or objects?

Stackoverflow is full of questions related to different types of String initialization. I understand how different is String s = "word" to String s = new String("word"). So no need to 'touch' that topic.
I noticed that different people refer that String pool stores constants/objects/literals.
Constants are understandable, as they are final, so they always 'stay' there. Yes, also duplicates aren't stored in SCP.
But I can't understand does SCP store objects or literals. They are totally different concepts. Object is an entity, while literal is just a value. So what is the correct answer to this. Does SCP store objects or literals? I know it can't be both :)
Literals are a chunk of source code that is delimited by ". For example, in the following line of source code:
String s = "Hello World";
"Hello World" is a string literal.
Objects are a useful abstraction for a meaningful bits of memory with data that (when grouped together) represents something, whether it be a Car, Person, or String.
The string pool stores String objects rather than String literals, simply because the string pool does not store source code.
You might hear people say "the string pool stores string literals". They (probably) don't mean that the string pool somehow has the source code "Hello World" in it. They (probably) mean that all the Strings represented by string literals in your source code will get put into the string pool. In fact, the Strings produced by constant expressions in your source code also gets added to the string pool automatically.
Strictly speaking, "literal" is not a value; It is a syntactic form. A String literal in Java is a double quote followed by some non-double-quote (or escaped double quote) characters, ending in another double quote. A "literal value" is a value that is created from a source-code literal, as opposed to an evaluated value such as a.concat(b). The core difference is that the literal value can be identified at compilation time, while an evaluated value can only be known during execution. This allows the compiler to store the literal values inside the compiled bytecode. (Since constants initialised by literal values are also known by the compiler at compile time, evaluations that only use constants can also be computed at compile time.)
In colloquial speech one can refer to a literal value as a "literal", but that may be the source of your confusion - a value is a value, whether its origin is a literal, or an evaluation.
I know it can't be both
The distinction between a literal value and an evaluated value is separate from a distinction between an object value and a primitive value. "foo" is a literal String value (and since Strings are objects, it is also an object). 3 is a literal primitive (integer) value. If x is currently 7, then 18 - x evaluates to a non-literal primitive value of 11. If y is currently "world!", then "Hello, " + y evaluates to a non-literal, non-primitive value "Hello, world!".
Nice question. The answer can be found through how String::intern() was implemented. From javadoc:
* When the intern method is invoked, if the pool already contains a
* string equal to this {#code String} object as determined by
* the {#link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {#code String} object is added to the
* pool and a reference to this {#code String} object is returned.
* <p>
So the String pool stores string object.
We can open the source code to confirm the answer. String::intern() is a native method and it's defined in StringTable::intern(), symbolTable.hpp
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
unsigned int hashValue = hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
oop found_string = the_table()->lookup(index, name, len, hashValue);
// Found
if (found_string != NULL) {
ensure_string_alive(found_string);
return found_string;
}
... ...
Handle string;
// try to reuse the string if possible
if (!string_or_null.is_null()) {
string = string_or_null;
} else {
string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
}
... ...
// Grab the StringTable_lock before getting the_table() because it could
// change at safepoint.
oop added_or_found;
{
MutexLocker ml(StringTable_lock, THREAD);
// Otherwise, add to symbol to table
added_or_found = the_table()->basic_add(index, string, name, len,
hashValue, CHECK_NULL);
}
ensure_string_alive(added_or_found);
return added_or_found;
}
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/f3108e56b502/src/share/vm/classfile/symbolTable.cpp

What is happening when you "alter" a string in Java using "+="?

I understand that a String variable in Java is immutable and can therefore not be changed.
String myString = "Hello.";
myString += " ";
myString += "My name is Kevin";
Each time we "add" something to this String(), we are effectively creating a new String(), but this has the same name as the string it is being concatenated with. Does this mean there are multiple references in memory with the variable "myString"?
Each time you "modify"/concatenate the String with +=, you're creating a new String object and replacing the reference named myString with the newly-created String. So no, there is only one reference in memory, but the object the reference points to changes each time. The string is immutable, so the object cannot be modified "in place".
String is an immutable class in Java. An immutable class is simply a class whose instances cannot be modified. All information in an instance is initialized when the instance is created and the information can not be modified. There are many advantages of immutable classes.
There is a great answer on the Programmer's StackExchange explaining why Strings are immutable in Java, and more details about how exactly this works.
The best way to do this is to just use the StringBuilder() class:
String myStringBuilder = new StringBuilder("Hello.");
myStringBuilder.append(" ");
myStringBuilder.append("My name is Kevin");
System.out.println(myStringBuilder.toString());
However, String concatenation is translated into StringBuilder operations automatically by modern Java compilers.
No , you can not access to previous reference and it's left for garbage collector to collect it. in other words there is only one reference in memory which holds the current value of variable("My Name is Kevin)
note that if you r gonna change a String variable a lot , you should use StringBuilder class.
here is link to Documentation of StringBuilder class
you also can find lots example for using this class on internet
https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html
also here is detailed answer of your question
When will a string be garbage collected in java
String myString = "Hello.";
The above create a new Object and put "Hello." into memory which myString is reference to the Object.
myString += " ";
Here you can look as myString = myString + " "; a " " String is created and put into memory and the concatenation will result to create a new String which is referenced by myString.
Note that String concatenation with "+" has a O(N2) complexity while StringBuilder has O(N) in complexity. It is becase new String is created for the concatenation result every time while StringBuilder instead contains a sequence of characters. Therefore String concatenation is less efficient than using a StringBuilder especially need to build up a large amount of String.
Java uses a string pool. This is an implementation of the concept of string interning.
In computer science, string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time- or space-efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool.
This means that for every string, a copy of that particular string is added to the string pool. Every variable that holds that exact string, points to that copy in the string pool.
The strings Hello., , and My name is Kevin are added to the string pool, since they're literals in the program.
String myString = "Hello.";
The variable myString starts pointing to the string Hello., which is already in the string pool.
myString += " ";
The string Hello. (note the extra space at the end) is added to the pool. The variable myString now points to that.
myString += "My name is Kevin";
The string Hello. My name is Kevin is added to the pool. The variable myString now points to that.
Strings in the pool that are no longer being referenced by variables, are eligible for garbage collection, so Hello. (with the space at the end), can now be garbage collected.
here your Code in which you define a String reference variable myString.
String is a immutable class, it means there is no modification can be made in object once it created.
Here "Hello" creates a String Object and refer the object by myString.
String myString = "Hello."; //create a Object String contain Hello and refer to myString
myString += " ";
myString += "My name is Kevin";
when myString+=" "; getting executed it creates another new object of String by concaticate "Hello" in it.
"Hello " a new Object created and myString refers to it. "Hello" is eligible for garbage Collection.
again when myString += "My name is Kevin"; getting executed, it creates another new Object of String by concatinate "Hello " in it.
Your new Object "Hello My Name is Kevin" is referred by myString reference Variable of String Type.
Now, Your both earlier Objects "Hello" and "Hello/s" is not referenced by any other reference variable, So, It is eligible for garbage Collection.
Thanks

How "==" works for objects?

public static void main(String [] a)
{
String s = new String("Hai");
String s1=s;
String s2="Hai";
String s3="Hai";
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s==s2);
System.out.println(s2==s3);
}
From the above code can anyone explain what is going behind when JVM encounters this line (s==s2) ?
It compares references - i.e. are both variables referring to the exact same object (rather than just equal ones).
s and s2 refer to different objects, so the expression evaluates to false.
s and s1 refer to the same objects (as each other) because of the assignment.
s2 and s3 refer to the same objects (as each other) because of string interning.
If that doesn't help much, please ask for more details on a particular bit. Objects and references can be confusing to start with.
Note that only string literals are interned by default... so even though s and s2 refer to equal strings, they're still two separate objects. Similarly if you write:
String x = new String("foo");
String y = new String("foo");
then x == y will evaluate to false. You can force interning, which in this case would actually return the interned literal:
String x = new String("foo");
String y = new String("foo");
String z = "foo";
// Expressions and their values:
x == y: false
x == z: false
x.intern() == y.intern(): true
x.intern() == z: true
EDIT: A comment suggested that new String(String) is basically pointless. This isn't the case, in fact.
A String refers to a char[], with an offset and a length. If you take a substring, it will create a new String referring to the same char[], just with a different offset and length. If you need to keep a small substring of a long string for a long time, but the long string itself isn't needed, then it's useful to use the new String(String) constructor to create a copy of just the piece you need, allowing the larger char[] to be garbage collected.
An example of this is reading a dictionary file - lots of short words, one per line. If you use BufferedReader.readLine(), the allocated char array will be at least 80 chars (in the standard JDK, anyway). That means that even a short word like "and" takes a char array of 160 bytes + overheads... you can run out of space pretty quickly that way. Using new String(reader.readLine()) can save the day.
== compars objects not the content of an object. s and s2 are different objects. If you want to compare the content use s.equals(s2).
Think of it like this.
Identical twins look the same but they are made up differently.
If you want to know if they "look" the same use the compare.
If you want to know they are a clone of each other use the "=="
:)
== compares the memory (reference) location of the Objects. You should use .equals() to compare the contents of the object.
You can use == for ints and doubles because they are primitive data types
I suppose you know that when you test equality between variables using '==', you are in fact testing if the references in memory are the same. This is different from the equals() method that combines an algorithm and attributes to return a result stating that two Objects are considered as being the same. In this case, if the result is true, it normally means that both references are pointing to the same Object. This leaves me wondering why s2==s3 returns true and whether String instances (which are immutable) are pooled for reuse somewhere.
It should be an obvious false. JVM does a thing like using the strings that exist in the Memory . Hence s2,s3 point to the same String that has been instantiated once. If you do something like s5="Hai" even that will be equal to s3.
However new creates a new Object. Irrespective if the String is already exisitng or not. Hence s doesnot equal to s3,s4.
Now if you do s6= new String("Hai"), even that will not be equal to s2,s3 or s.
The literals s2 and s3 will point to the same string in memory as they are present at compile time. s is created at runtime and will point to a different instance of "Hai" in memory. If you want s to point to the same instance of "Hai" as s2 and s3 you can ask Java to do that for you by calling intern. So s.intern == s2 will be true.
Good article here.
You are using some '==' overload for String class...

String can't change. But int, char can change

I've read that in Java an object of type String can't change. But int and char variables can. Why is it? Can you give me an example?
Thank you.
(I am a newer -_- )
As bzabhi said, strings are immutable in Java. This means that a string object will never change. This does not mean you can not change string variables, just that you cannot change the underlying memory representation of the string. for an example:
String str = "Hello";
str += " World!";
Following the execution of these lines, str will point to a new string in memory. The original "Hello" string still exists in memory, but most likely it will not be there for long. Assuming that there are no extenuating circumstances, nothing will be pointing at the original string, so it will be garbage collected.
I guess the best way to put this would be to say that when line 2 of the example executes, a new string in memory is created from the concatenation of the original string and the string being added to it. The str variable, which is just a reference to a memory location, is then changed to point at the new variable that was just created.
I am not particularly knowledgeable on the point, but, as I understand it, this is what happens with all "non-primitive" values. Anything that at some point derives from Object follows these rules. Primitive values, such as ints, bools, chars, floats and doubles allow the actual value in memory to be changed. So, from this:
int num = 5;
num += 2;
the actual value in memory changes. Rather than creating a new object and changing the reference, this code sample will simply change the value in memory for the num variable.
As for why this is true, it is simply a design decision by the makers of Java. I'm sure someone will comment on why this was made, but that isn't something I know.
int and char can't change either. As with strings, you can put a different value into the same variable, but an integer itself doesn't change. 3 will always be 3; you can't modify it to be 4.
String is an immutable type (the value inside of it cannot change). The same is true for all primitive types (boolean, byte, char, short, int, long, float, and double).
int x;
String s;
x = 1;
x = 2;
s = "hello";
s = "world";
x++; // x = x + 1;
x--; // x = x - 1;
As you can see, in no case can you alter the constant value (1, 2, "hello", "world") but you can alter where they are pointing (if you warp your mind a bit and say that an int variable points at a constant int value).
I'm not sure that it is possible to show (by example) that Strings cannot change. But you can confirm this by reading the description section of Javadoc for the String class, then reading the methods section and noting that there are no methods that can change a String.
EDIT: There are many reasons why Strings are designed to be immutable in Java. The most important reason is that immutable Strings are easier to use correctly than mutable ones. And if you do need the mutable equivalent of a String for some reason, you can use the StringBuilder (or StringBuffer) class.
It's also worthwhile to note that since strings are immutable, that if they are passed into a method, they can't be modified inside of the method and then have those changes seen outside of the method scope.
public void changeIt(String s) {
// I can't do anything to s here that changes the value
// original string object passed into this method
}
public void changeIt(SomeObject o) {
// if SomeObject is mutable, I can do things to it that will
// be visible outside of this method call
}
This little article can probably explain it better than I can: http://www.jchq.net/tutorial/09_02Tut.htm
Strings are immutable in java. Nevertheless, you can still append or prepend values to strings. By values, I mean primitive data types or other strings.
However, a StringBuffer is mutable, i.e. it can be changed in memory (a new memory block doesn't have to be allocated), which makes it quite efficient. Also, consider the following example:
StringBuffer mystringbuffer = new StringBuffer(5000);
for (int i = 0; i<=1000; i++)
{
mystringbuffer.append ( 'Number ' + i + '\n');
}
System.out.print (mystringbuffer);
Rather than creating one thousand strings, we create a single object (mystringbuffer), which can expand in length. We can also set a recommended starting size (in this case, 5000 bytes), which means that the buffer doesn't have to be continually requesting memory when a new string is appended to it.
While a StringBuffer won't improve efficiency in every situation, if your application uses strings that grow in length, it would be efficient. Code can also be clearer with StringBuffers, because the append method saves you from having to use long assignment statements.

Is there a difference between String concat and the + operator in Java? [duplicate]

This question already has answers here:
Closed 13 years ago.
Duplicate
java String concatenation
I'm curious what is the difference between the two.
The way I understand the string pool is this:
This creates 3 string objects in the string pool, for 2 of those all references are lost.
String mystr = "str";
mystr += "end";
Doesn't this also create 3 objects in the string pool?
String mystr = "str";
mystr = mystr.concat("end")
I know StringBuilder and StringBuffer are much more efficient in terms of memory usage when there's lots of concatination to be done. I'm just curious if there's any difference between the + operator and concat in terms of memory usage.
There's no difference in this particular case; however, they're not the same in general.
str1 += str2 is equivalent to doing the following:
str1 = new StringBuilder().append(str1).append(str2).toString();
To prove this to yourself, just make a simple method that takes two strings and +='s the first string to the second, then examine the disassembled bytecode.
By contrast, str1.concat(str2) simply makes a new string that's the concatenation of str1 and str2, which is less expensive for a small number of concatenated strings (but will lose to the first approach with a larger number).
Additionally, if str1 is null, notice that str1.concat(str2) throws a NPE, but str1 += str2 will simply treat str1 as if it were null without throwing an exception. (That is, it yields "null" concatenated with the value of str2. If str2 were, say, "foo", you would wind up with "nullfoo".)
Update: See this StackOverflow question, which is almost identical.
The important difference between += and concat() is not performance, it's semantics. concat() will only accept a string argument, but + (or +=) will accept anything. If the non-string operand is an object, it will be converted to a string by calling toString() on it; a primitive will be converted as if by calling the appropriate method in the associated wrapper class, e.g., Integer.toString(theInt); and a null reference becomes the string "null".
Actually, I don't know why concat() even exists. People see it listed in the API docs and assume it's there for a good reason--performance being the most obvious reason. But that's a red herring; if performance is really a concern, you should be using a StringBuilder, as discussed in the thread John linked to. Otherwise, + or += is much more convenient.
EDIT: As for the issue of "creating objects in the string pool," I think you're misunderstanding what the string pool is. At run-time, the actual character sequences, "str" and "end" will be stored in a dedicated data structure, and wherever you see the literals "str" and "end" in the source code, the bytecode will really contain references to the appropriate entries in that data structure.
In fact, the string pool is populated when the classes are loaded, not when the code containing the string literals is run. That means each of your snippets only creates one object: the result of the concatenation. (There's also some object creation behind the scenes, which is a little different for each of the techniques, but the performance impact is not worth worrying about.)
The way I understand the string pool
is this:
You seem to have a misconception concerning that term. There is no such thing as a "string pool" - the way you're using it, it looks like you just mean all String object on the heap. There is a runtime constant pool which contains, among many other things, compile-time String constants and String instances returned from String.intern()
Unless the argument to concat is an empty string, then
String mystr = "str";
mystr = mystr.concat("end")
will also create 3 strings.
More info: https://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html.

Categories