How do String objects work (like immutable objects)? - java

I have these two situations:
String s = "aa";
s = s + " aa";
System.out.println(s);
//......
that work fine! It prints aa aa.
But there is a problem:
String s = "aa";
this.addStringToStatement(s, " aa");
System.out.println(s);
//...
private void addStringToStatement(String statement, Object value) {
statement += value;
}
It prints: aa.
What is the reason??
Thanks!

There are two issues to understand here.
The String append operator will create a new immutable String object. The expression s + value is a different object in memory from s.
In your function addStringToStatement when you execute statement += value; you aren't changing the value of the variable s, rather you are reassigning the local pointer statement to a new String instance.
EDIT: Fixed usual noob mistake: In Java, object references are passed, not the objects themselves.

This is because in Java a reference is passed by value. Here when you passed s and " aa" as two parameters.
In the method statement variable (which has reference of s) is altered to point to something else ie "aa aa". Note only the statement reference is passed, s is still pointing to "aa".
So when you print s you get what is expected :)

this is because of how passing by value works in Java, you need to do something like this:
String s = "aa";
s = this.addStringToStatement(s, " aa");
System.out.println(s);
//...
private string addStringToStatement(String statement, Object value) {
statement += value;
return statement;
}

Strings in Java are immutable. If you have a String s="aa", you only have a reference to the String "aa" inside the JVM. If you want the String "aa aa" assigned to s, you assign only the reference (address) to "aa aa" (another String inside the JVM) to s, "aa" lurks still somewhere in the JVM.
The statement "Java references are passed by value" is somewhat confusing (if true). If you use a StringBuilder sb and give this StringBuilder to a function, the reference is "copied" but still points to the same object as sb:
public static void main(String[] args) {
final StringBuilder sb = new StringBuilder();
f(sb);
System.out.println(sb);
}
private static void f(final StringBuilder sb) {
sb.append("aa aa");
}

You have to return the "statement" variable. Without the "this.*" part.
String s = "aa";
s = addStringToStatement(s, " aa");
System.out.println(s);
//...
private String addStringToStatement(String statement, Object value) {
statement += value;
return statement;
}

#Frank Meißner (new to this, can't reply to answers yet)
Just to clarify the difference between String and StringBuilder (in case anyone reading this is confused), while both store the CharSequence they hold as a char[], the char[] within String cannot be changed, thus a new String has to be created for every alteration. In the case of a StringBuilder, there are methods like StringBuilder.append(String) that can change the internal char[] of the StringBuilder, so if StringBuilder.append(String) is called, no new object will have to be created for the content of the StringBuilder to change.
As per Frank Meißner's example, System.out.println(sb); will print "aa aa", since the method append(String) was called on the StringBuilder sb. final doesn't hurt here since the identity of sb isn't changed, only its state.

+= in case of string doesn't modify string itself but produce new string. in case of your method you set this new string reference to local variable (parameter)

Java references are passed by value. When you pass a String to a method and it changes inside it points to different String. You can either return the String after appending or use StringBuffer as argument.

Related

Incompatible Types: Returning a new String object

I've been working on a little project writing my own custom String methods. (replace,concat, etc...) to manipulate strings in an object oriented design.
In my class definition (MyString) I wrote a concat() method that has a return type of a MyString.
public MyString concat(MyString sent)
{
char[] newString = new char[sequence.length + sent.sequence.length];
for(int i = 0; i< sequence.length;i++)
{
newString[i] = sequence[i];
}
for(int i = sequence.length; i < newString.length; i++)
{
newString[i] = sent.charAt(i - sequence.length);
}
sent.sequence = newString;
return sent;
In my driver A user will enter a string. and then be prompted to enter another string to be concatenated. when I go to call the method I'm getting an incompatible types error saying the String I'm sending into it (compString) can't be converted to a new MyString. I created a new MyString object, and sent in the new String, which I thought was the right thing to do...
MyString ms = new MyString(compString);
System.out.println("Calling the concat() method: " + ms.concat(compString) );
I want to concatenate compString onto the original string, both of with are MyStrings. How would I go about calling this method? "ms" being the reference variable to the original string. Do I need a new MyString object in order to accomplish this?
public MyString(String sent)
{
origional = new String(sent);
sequence = origional.toCharArray();
}
Here is my constructor just in case.
You're passing a String into your concat() method, which expect MyString. Try wrapping it in your class first:
ms.concat(new MyString(compString))
I have to admit, this still doesn't make much sense. ms is already a wrapper for compString. Are you trying to concat a string to itself? Then just do ms.concat(ms).
You need to override the toString function so that the println() function will properly print out your custom string.
You also need to match the expected MyString type parameter for your concat(MyString sent) function.
Something like:
class MyString {
public String toString()
{
return sequence;
}
}
MyString ms = new MyString(compString);
// making assumption that compString is a standard string
System.out.println("Calling the concat() method: " + ms.concat(new MyString(compString)) );

Why does String not work as "pass by reference" in spite of being an array of characters

I understand that on passing an array asn argument to a function, and making some change to the elements of the array inside the function, the changes will be reflected in the calling function as well, since arrays operates directly on memory (call by reference)
However, why is it that the same behavior does not apply to Strings? I was expecting Strings as well to work in the same way since a String is basically an array of characters.
Please see my code below.
I pass in a String (character array) as well as an int array in to a function and make some changes in it. On printing these in main, I see that the String remains unaffected whereas the changes to the array are reflected.
import java.util.Arrays;
public class TestString
{
public static void main(String[] args)
{
String s = "hello";
int[] a = new int[5];
Arrays.fill(a, -1);
fun(s,a);
System.out.println(s);
System.out.println(a[0]);
}
static void fun(String s, int[] a)
{
s = "world";
a[0] = 99;
}
}
Output
hello
99
First, the claim that a String is an array of characters is wrong. A String is an object, that has methods and is designed specifically not to allow any changes to be made in it.
Second, what you are doing is not changing some element of the parameter. You are changing the parameter variable. The parameter variable is basically a local variable, which receives a reference to the string that was passed as argument. Doing this:
s = "world";
Is not changing the string that was passed. It replaces contents of the local variable s with a new string. Since Java is always pass by value, this is not reflected outside of the method. It would be the same if you had:
a = new int[30];
inside the method. Outside of it you would still see the 5-element int[] that you passed inside.
a[0] = 99;
Is changing an element inside the array. So it looks at a, checks what it refers to, goes to that referred array, and changes its 0th element.
Since String is designed to be immutable, there is no way to do something similar in it. You can't do something like:
s.setCharacter(0,'a'); // This doesn't exist in Java
But you can do this with mutable objects. For example, if you had:
public static void manipulateStringBuilder( StringBuilder sb ) {
sb.append(": manipulated");
sb = new StringBuilder("New value assigned");
}
Then you could write something like:
StringBuilder sb = new StringBuilder("My string");
System.out.println(sb);
manipulateStringBuilder( sb );
System.out.println(sb);
And the output would be:
My string
My string: manipulated
This is because StringBuilder is a mutable object, combined with the fact that the value that you assigned to sb inside your method is never seen outside of it.
Because Strings in java are immutable. Every "change" done to a string does not changes the original string but creates a new String object.
It is because Strings are immutable. If you want to change the value of the String you should return it from the method and store it in the variable s again.
import java.util.Arrays;
public class TestString
{
public static void main(String[] args)
{
String s = "hello";
int[] a = new int[5];
Arrays.fill(a, -1);
s = fun(s,a);
System.out.println(s);
System.out.println(a[0]);
}
static String fun(String s, int[] a)
{
s = "world";
a[0] = 99;
return s;
}
}
I expect it will be helpful for you!
Java is not call by reference, but call by value, it is just that it passes references as values. More details here.
Strings are immutable, so you can't change the content (the char array) of a String, you can just replace it with a different one, i.e. you are changing the reference. But since the reference is passed by value, the change is not visible outside a method.
Actually you can change the content of String using reflection, which results in very interesting behavior. You use this only when you want to play a prank on a coworker.

what is diff b/w String & StringBuilder object creation in terms of assigning reference to it's object?

This is a sample code, I am confused at it's behavior.
public class RefCheckForStrings {
StringBuilder sb=new StringBuilder("abc");
sb.append("def"); //error syntax error
//System.out.println(sb);
String s="abc";
s.concat("def"); //error syntax error
//System.out.println(s);*/
public static void set(){
String s="abc";
s.concat("def");
System.out.println(s); // prints abc
String str=s.concat("def");
System.out.println(str); // prints abcdef
final StringBuilder sb=new StringBuilder("abc");
sb.append("def");
System.out.println(sb); //prints abcdef
}
why there is syntax error while modifying object in class ? I think it's same reason as System.out.print() also not working there... But i could not understand it fully through google search... Please explain or give a reference to get it clear..
In case of String object, if we modify it, Does the reference point to a new object(The modified one created as another object) & for StringBuilder, does the reference points the same object(the same object has the modification)... I can think these two answer is YES, and that is basic difference b/w String& StringBilder. Am i correct or missing any concepts of String.... Thanks in Advance
Class body cannot have statements which are not assignments. To do that, you have to put them in blocks:
public class RefCheckForStrings {
StringBuilder sb=new StringBuilder("abc");
{
sb.append("def");
System.out.println(sb);
}
String s="abc";
{
s.concat("def");
System.out.println(s);
}
}
Strings are immutable in java. It means that you cannot change their values. Calling "abc".concat("def") returns a new String that you'll have to assign to a new variable to capture it.
String ad = "abc".concat("def");
Whereas StringBuilders are mutable so calling concat on them changes their value in-place.
StringBuilder sb = new StringBuilder("abc");
sb.concat("def");
// value in sb is now "abcdef"
You have to do those operations as a part of a method...
public class RefCheckForStrings {
StringBuilder sb=new StringBuilder("abc");
sb.append("def"); // You can do this only inside a method
//System.out.println(sb);
String s="abc";
s.concat("def"); // You can do this only inside a method
//System.out.println(s);*/
}
Possibly as below... to take an example of doing these in a constructor
public class RefCheckForStrings {
StringBuilder sb;
String s;
public RefCheckForStrings()
{
sb=new StringBuilder("abc");
s = "abc";
sb.append("def");
s.concat("def");
}
}
There is another way of doing the same thing without using a method in Java 7... it is as shown below...
public class RefCheckForStrings {
StringBuilder sb=new StringBuilder("abc");
{
sb.append("def");
System.out.println(sb);
}
String s="abc";
{
s.concat("def");
System.out.println(s);
}
}
To answer your second question... Strings are immutable, in other words. Once you assign address of a string to a variable, the string located in that address cannot be changed. if you do s.concat() when s is a string, a new string will be created in memory which is a concatenated form. But address of s doesn't directly change. So, you have explicitly tell s.concat() as s = s.concat("abc");. Where as the way String builders are developed, they can be directly changed in the location where they are created without having to create a new copy in the memory. So they are mutable and don't have to assign any reference back to the string builder object.
If you create a string s and if you assume the string "abc" is assigned to it, assume "abc" is stored at address 1001 if you do s+"def" the resulting string may be stored at address 2001, but s will still be pointing to 1001. instead if you do s = s + "def", the location of where s is pointed to will also change, so now s is pointing to 2001. The string "abc" will still be located at 1001 and it will be cleaned by garbage collector if not used for some time.
There's a syntax error because that's not where those statements go.
Strings are immutable. Any method that "modifies" the String object is in fact returning a new String object so you need to reassign it to the variable. The StringBuilder isn't immutable, methods that modify it (append for example) don't return a new StringBuilder object.

What's the difference between return (string expr) and return New String(string expr)?

Is there a difference between these two methods?
public String toString() {
return this.from.toString() + this.to.toString();
}
public String toString() {
return new String(this.from.toString() + this.to.toString());
}
(assuming, of course, that the from.toString() and to.toString() methods are returning Strings).
Basically I'm confused about String handling in Java, because sometimes strings are treated like a primitive type even though they are class instances.
There is no difference in real.
as both of your function has return type String, creating a new String() is just a overhead. it like wrapping a string to again to a string and create a new string in pool which in real has no advantage.
But one major difference in primitive type and String object is that class String always create new string.
String str = "my string";
if "my string" already exists in String pool. then it will use the same string instead of creating new.
This is the reason why when,
String str1= "my string";
String str2 ="my string";
str1==str2? --> will return true
The result of above will be true, because same String object from pool is used.
but when you do,
String str = new String("new string");
Always, a new String object is created, irrespective of a same one already exists in pool or not.
so comparing:
String str1 = new String("new string");
String str2 = new String("new string");
str1==str2 --> will return false
There is a difference, if at some point you previously defined a String "ABC". Java interns strings, so when you don't explicitly state that you want a new object, it will return an object that has the same value. So for example.
String abc = "abc";
// Some code.
return new String("abc"); // This will be a new object.
Whereas if you do this:
String abc = "abc";
// Some code.
return "abc"; // This will be the above object.
This is because it's pointless for the JVM to waste memory with objects of the same value, so it stores them in memory and waits for you to need / use them again!
Which one do you go for?
More often than not the String interning process won't hamper you too much, so you're usually okay going for the former.
The second one has an extra overhead.. In the second method you are initializing the string one more time that the first one ... something like
String s = "something";
return s;
vs
return new(s);
apart from that both will do the exact same task.
return new String(this.from.toString() + this.to.toString());
Above statement will create 2 objects.
1st object is referring to concatenated value of this.from.toString() + this.to.toString(). This doesn't have reference.
2nd object is created because of new operator.
return this.from.toString() + this.to.toString();
This will create 1 object on heap memory area.

Immutability of Strings in Java

Consider the following example.
String str = new String();
str = "Hello";
System.out.println(str); //Prints Hello
str = "Help!";
System.out.println(str); //Prints Help!
Now, in Java, String objects are immutable. Then how come the object str can be assigned value "Help!". Isn't this contradicting the immutability of strings in Java? Can anybody please explain me the exact concept of immutability?
Edit:
Ok. I am now getting it, but just one follow-up question. What about the following code:
String str = "Mississippi";
System.out.println(str); // prints Mississippi
str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!
Does this mean that two objects are created again ("Mississippi" and "M!ss!ss!pp!") and the reference str points to a different object after replace() method?
str is not an object, it's a reference to an object. "Hello" and "Help!" are two distinct String objects. Thus, str points to a string. You can change what it points to, but not that which it points at.
Take this code, for example:
String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"
Now, there is nothing1 we could do to s1 that would affect the value of s2. They refer to the same object - the string "Hello" - but that object is immutable and thus cannot be altered.
If we do something like this:
s1 = "Help!";
System.out.println(s2); // still prints "Hello"
Here we see the difference between mutating an object, and changing a reference. s2 still points to the same object as we initially set s1 to point to. Setting s1 to "Help!" only changes the reference, while the String object it originally referred to remains unchanged.
If strings were mutable, we could do something like this:
String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"
Edit to respond to OP's edit:
If you look at the source code for String.replace(char,char) (also available in src.zip in your JDK installation directory -- a pro tip is to look there whenever you wonder how something really works) you can see that what it does is the following:
If there is one or more occurrences of oldChar in the current string, make a copy of the current string where all occurrences of oldChar are replaced with newChar.
If the oldChar is not present in the current string, return the current string.
So yes, "Mississippi".replace('i', '!') creates a new String object. Again, the following holds:
String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects
Your homework for now is to see what the above code does if you change s1 = s1.replace('i', '!'); to s1 = s1.replace('Q', '!'); :)
1 Actually, it is possible to mutate strings (and other immutable objects). It requires reflection and is very, very dangerous and should never ever be used unless you're actually interested in destroying the program.
The object that str references can change, but the actual String objects themselves cannot.
The String objects containing the string "Hello" and "Help!" cannot change their values, hence they are immutable.
The immutability of String objects does not mean that the references pointing to the object cannot change.
One way that one can prevent the str reference from changing is to declare it as final:
final String STR = "Hello";
Now, trying to assign another String to STR will cause a compile error.
Light_handle I recommend you take a read of Cup Size -- a story about variables and Pass-by-Value Please (Cup Size continued). This will help a lot when reading the posts above.
Have you read them? Yes. Good.
String str = new String();
This creates a new "remote control" called "str" and sets that to the value new String() (or "").
e.g. in memory this creates:
str --- > ""
str = "Hello";
This then changes the remote control "str" but does not modify the original string "".
e.g. in memory this creates:
str -+ ""
+-> "Hello"
str = "Help!";
This then changes the remote control "str" but does not modify the original string "" or the object that the remote control currently points to.
e.g. in memory this creates:
str -+ ""
| "Hello"
+-> "Help!"
Lets break it into some parts
String s1 = "hello";
This Statement creates string containing hello and occupy space in memory i.e. in Constant String Pool and and assigned it to reference object s1
String s2 = s1;
This statement assigns the same string hello to new reference s2
__________
| |
s1 ---->| hello |<----- s2
|__________|
Both references are pointing to the same string so output the same value as follows.
out.println(s1); // o/p: hello
out.println(s2); // o/p: hello
Though String is immutable, assignment can be possible so the s1 will now refer to new value stack.
s1 = "stack";
__________
| |
s1 ---->| stack |
|__________|
But what about s2 object which is pointing to hello it will be as it is.
__________
| |
s2 ---->| hello |
|__________|
out.println(s1); // o/p: stack
out.println(s2); // o/p: hello
Since String is immutable Java Virtual Machine won't allow us to modify string s1 by its method. It will create all new String object in pool as follows.
s1.concat(" overflow");
___________________
| |
s1.concat ----> | stack overflow |
|___________________|
out.println(s1); // o/p: stack
out.println(s2); // o/p: hello
out.println(s1.concat); // o/p: stack overflow
Note if String would be mutable then the output would have been
out.println(s1); // o/p: stack overflow
Now you might be surprised why String has such methods like concat() to modify. Following snippet will clear your confusion.
s1 = s1.concat(" overflow");
Here we are assigning modified value of string back to s1 reference.
___________________
| |
s1 ---->| stack overflow |
|___________________|
out.println(s1); // o/p: stack overflow
out.println(s2); // o/p: hello
That's why Java decided String to be a final class Otherwise anyone can modify and change the value of string.
Hope this will help little bit.
The string object that was first referenced by str was not altered, all that you did was make str refer to a new string object.
The String will not change, the reference to it will. You are confusing immutability with the concept of final fields. If a field is declared as final, once it has been assigned, it cannot be reassigned.
Regarding the replace part of your question, try this:
String str = "Mississippi";
System.out.println(str); //Prints Mississippi
String other = str.replace("i", "!");
System.out.println(str); //still prints Mississippi
System.out.println(other); // prints M!ss!ss!pp!
Though java tries to ignore it, str is nothing more than a pointer. This means that when you first write str = "Hello";, you create an object that str points to. When you reassign str by writing str = "Help!";, a new object is created and the old "Hello" object gets garbage collected whenever java feels like it.
Immutability implies that the value of an instantiated object cannot change, you can never turn "Hello" into "Help!".
The variable str is a reference to an object, when you assign a new value to str you aren't changing the value of the object it references, you are referencing a different object.
String class is immutable, and you can not change value of immutable object.
But in case of String, if you change the value of string than it will create new string in string pool and than your string reference to that value not the older one. so by this way string is immutable.
Lets take your example,
String str = "Mississippi";
System.out.println(str); // prints Mississippi
it will create one string "Mississippi" and will add it to String pool
so now str is pointing to Mississippi.
str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!
But after above operation,
one another string will be created "M!ss!ss!pp!"
and it will be add to String pool. and
now str is pointing to M!ss!ss!pp!, not Mississippi.
so by this way when you will alter value of string object it will create one more object and will add it to string pool.
Lets have one more example
String s1 = "Hello";
String s2 = "World";
String s = s1 + s2;
this above three line will add three objects of string to string pool.
1) Hello
2) World
3) HelloWorld
For those wondering how to break String immutability in Java...
Code
import java.lang.reflect.Field;
public class StringImmutability {
public static void main(String[] args) {
String str1 = "I am immutable";
String str2 = str1;
try {
Class str1Class = str1.getClass();
Field str1Field = str1Class.getDeclaredField("value");
str1Field.setAccessible(true);
char[] valueChars = (char[]) str1Field.get(str1);
valueChars[5] = ' ';
valueChars[6] = ' ';
System.out.println(str1 == str2);
System.out.println(str1);
System.out.println(str2);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Output
true
I am mutable
I am mutable
Use:
String s = new String("New String");
s.concat(" Added String");
System.out.println("String reference -----> "+s); // Output: String reference -----> New String
If you see here I use the concat method to change the original string, that is, "New String" with a string " Added String", but still I got the output as previous, hence it proves that you can not change the reference of object of String class, but if you do this thing by StringBuilder class it will work. It is listed below.
StringBuilder sb = new StringBuilder("New String");
sb.append(" Added String");
System.out.println("StringBuilder reference -----> "+sb);// Output: StringBuilder reference -----> New String Added String
Like Linus Tolvards said:
Talk is cheap. Show me the code
Take a look at this:
public class Test{
public static void main(String[] args){
String a = "Mississippi";
String b = "Mississippi";//String immutable property (same chars sequence), then same object
String c = a.replace('i','I').replace('I','i');//This method creates a new String, then new object
String d = b.replace('i','I').replace('I','i');//At this moment we have 3 String objects, a/b, c and d
String e = a.replace('i','i');//If the arguments are the same, the object is not affected, then returns same object
System.out.println( "a==b? " + (a==b) ); // Prints true, they are pointing to the same String object
System.out.println( "a: " + a );
System.out.println( "b: " + b );
System.out.println( "c==d? " + (c==d) ); // Prints false, a new object was created on each one
System.out.println( "c: " + c ); // Even the sequence of chars are the same, the object is different
System.out.println( "d: " + d );
System.out.println( "a==e? " + (a==e) ); // Same object, immutable property
}
}
The output is
a==b? true
a: Mississippi
b: Mississippi
c==d? false
c: Mississippi
d: Mississippi
a==e? true
So, remember two things:
Strings are immutable until you apply a method that manipulates and creates a new one (c & d cases).
Replace method returns the same String object if both parameters are the same
String is immutable. Which means that we can only change the reference.
String a = "a";
System.out.println("String a is referencing to "+a); // Output: a
a.concat("b");
System.out.println("String a is referencing to "+a); // Output: a
a = a.concat("b");
System.out.println("String a has created a new reference and is now referencing to "+a); // Output: ab
In Java, objects are generally accessed by references. In your piece of code str is a reference which is first assigned to "Hello" (an automatic created object or fetched from constant pool) and then you assigned another object "Help!" to same reference. A point to note is the reference is the same and modified, but objects are different. One more thing in your code you accessed three objects,
When you called new String().
When you assigned "hello".
When you assigned "help!".
Calling new String() creates a new object even if it exists in string pool, so generally it should not be used. To put a string created from new String () into string pool you can try the intern() method.
I hope this helps.
Immutability I can say is that you cannot change the String itself. Suppose you have String x, the value of which is "abc". Now you cannot change the String, that is, you cannot change any character/s in "abc".
If you have to change any character/s in the String, you can use a character array and mutate it or use StringBuilder.
String x = "abc";
x = "pot";
x = x + "hj";
x = x.substring(3);
System.out.println(x);
char x1[] = x.toCharArray();
x1[0] = 's';
String y = new String(x1);
System.out.println(y);
Output:
hj
sj
Or you can try:
public class Tester
{
public static void main(String[] args)
{
String str = "Mississippi";
System.out.println(str); // prints Mississippi
System.out.println(str.hashCode());
str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!
System.out.println(str.hashCode());
}
}
This will show how the hashcode changes.
String is immutable means that you cannot change the object itself, but you can change the reference to the object. When you called a = "ty", you are actually changing the reference of a to a new object created by the String literal "ty". Changing an object means to use its methods to change one of its fields (or the fields are public and not final, so that they can be updated from outside without accessing them via methods), for example:
Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"
While in an immutable class (declared as final, to prevent modification via inheritance)(its methods cannot modify its fields, and also the fields are always private and recommended to be final), for example String, you cannot change the current String but you can return a new String, i.e:
String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"
Here immutability means that instance can point to other reference but the original content of the string would not be modified at the original reference.
Let me explain by first example given by you.
First str is pointing to "Hello" ,its Ok upto this.
Second time its pointing to "Help!".
Here str started pointing to "Help!" and the reference of "Hello" string is lost and we can not get that back.
In fact when str would try to modify the existing content,then another new string will be generated and str will start to point at that reference.
So we see that string at original reference is not modified but that is safe at its reference and instance of object started pointing at different reference so immutability is conserve.
Super late to the answer, but wanted to put a concise message from author of the String class in Java
Strings are constant; their values cannot be changed after they are
created. String buffers support mutable strings. Because String
objects are immutable they can be shared.
It can be derived from this documentation that anything that changes string, returns different object (which could be new or interned and old).
The not so subtle hint about this should come from the function signature.
Think about it, 'Why did they make a function on an object return an object instead of status?'.
public String replace(char oldChar, char newChar)
Also one more source which makes this behaviour explicit (From replace function documentation)
Returns a new string resulting from replacing all occurrences of
oldChar in this string with newChar.
Source: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)
author Lee Boynton
author Arthur van Hoff
author Martin Buchholz
author Ulf Zibis
Source: JavaDoc of String.
The Object string - methods itself is made to be "immutable".
This action produces no changes: "letters.replace("bbb", "aaa");"
But assigning data does cause changes to the Strings content to change:
letters = "aaa";
letters=null;
System.out.println(letters);
System.out.println(oB.hashCode());
System.out.println(letters);
letters = "bbbaaa";
System.out.println(oB.hashCode());
System.out.println(letters);
//The hashcode of the string Object doesn't change.
If HELLO is your String then you can't change HELLO to HILLO. This property is called immutability property.
You can have multiple pointer String variable to point HELLO String.
But if HELLO is char Array then you can change HELLO to HILLO. Eg,
char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this
Programming languages have immutable data variables so that it can be used as keys in key, value pair.
I would explain it with simple example
consider any character array : e.g. char a[]={'h','e','l','l','o'};
and a string :
String s="hello";
on character array we can perform operations like printing only last three letters using iterating the array;
but in string we have to make new String object and copy required substring and its address will be in new string object.
e.g.
***String s="hello";
String s2=s.substrig(0,3);***
so s2 will have "hel";
String in Java in Immutable and Final just mean it can't be changed or modified:
Case 1:
class TestClass{
public static void main(String args[]){
String str = "ABC";
str.concat("DEF");
System.out.println(str);
}
}
Output: ABC
Reason: The object reference str is not changed in fact a new object
"DEF" is created which is in the pool and have no reference at all
(i.e lost).
Case 2:
class TestClass{
public static void main(String args[]){
String str="ABC";
str=str.concat("DEF");
System.out.println(str);
}
}
Output: ABCDEF
Reason: In this case str is now referring to a new object "ABCDEF"
hence it prints ABCDEF i.e. previous str object "ABC" is lost in pool with no reference.
Because String is immutable so changes will not occur if you will not assign the returned value of function to the string.so in your question assign value of swap function  returned value to s.
s=swap(s, n1, n2) ;then the value of string s will change.
I was also getting the unchanged value when i was writing the program to get some permutations string(Although it is not giving all the permutations but this is for example to answer your question)
Here is a example.
> import java.io.*;  public class MyString { public static void
> main(String []args)throws IOException {  BufferedReader br=new
> BufferedReader(new InputStreamReader(System.in));  String
> s=br.readLine().trim(); int n=0;int k=0;  while(n!=s.length()) {
> while(k<n){  swap(s,k,n); System.out.println(s); swap(s,k,n); k++; }
> n++; } }  public static void swap(String s,int n1,int n2) { char temp;
> temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s);
> sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString();
> } }
but i was not getting the permuted values of the string from above code.So I assigned the returned value of the swap function to the string and got changed values of string. after assigning the returned value i got the permuted values of string.
/import java.util.*; import java.io.*; public class MyString { public static void main(String []args)throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
String s=br.readLine().trim(); int n=0;int k=0; 
while(n!=s.length()){ while(k<n){ s=swap(s,k,n); 
System.out.println(s); s=swap(s,k,n); k++; } n++; } } 
public static String swap(String s,int n1,int n2){
char temp; temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s); sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString(); return s; } }
public final class String_Test {
String name;
List<String> list=new ArrayList<String>();
public static void main(String[] args) {
String_Test obj=new String_Test();
obj.list.add("item");//List will point to a memory unit- i.e will have one Hashcode value #1234
List<String> list2=obj.list; //lis1 also will point to same #1234
obj.list.add("new item");//Hashcode of list is not altered- List is mutable, so reference remains same, only value in that memory location changes
String name2=obj.name="Myname"; // name2 and name will point to same instance of string -Hashcode #5678
obj.name = "second name";// String is Immutable- New String HAI is created and name will point to this new instance- bcoz of this Hashcode changes here #0089
System.out.println(obj.list.hashCode());
System.out.println(list2.hashCode());
System.out.println(list3.hashCode());
System.out.println("===========");
System.out.println(obj.name.hashCode());
System.out.println(name2.hashCode());
}
}
Will produce out put something like this
1419358369
1419358369
103056
65078777
Purpose of Immutable object is that its value should not be altered once assigned.
It will return new object everytime you try to alter it based on the implementation.
Note: Stringbuffer instead of string can be used to avoid this.
To your last question :: u will have one reference , and 2 strings in string pool..
Except the reference will point to m!ss!ss!pp!

Categories