Is it correct to say that immutable objects are created by deep copy everytime we want to change/reference original object, while mutable objects are created by shallow copy when we create another reference.
For example:
String s1 = "s";
String s2 = s1;
and:
Person p1 = new Person();
Person p2 = p1;
As far as I'm concerned, s2 will get it own copy of "s" (not a copy of reference).
How this fit the String pool concept with single instances of String literals?
In case of Person we will have two references to one Person instance right?
Immutable objects cannot be changed. Their state remains constant after creation. Thus, "s" is constant. But the references that point to it could change.
String s1 = "s";
String s2 = s1;
Here, "s" is an immutable object (String), s1 and s2are just references.
Defensive copies are used to prevent state changes on an Object - part of the immutability story , by returning a new Object with the same values.
PS : You are not doing deep copying here. You are just re-assigning references.
Related
String s1=new String("Java"); /* 1st object created */
String s2="Tech"; /* 2nd Object */
s1+=s2;
I'm confusing here whether new object created or result stored in the previous object.
How many Objects created
str1 += str2
is equivalent to doing the following:
str1 = new StringBuilder().append(str1).append(str2).toString();
Final call to toString will create a new object and the reference will be hold by variable str1 here in 3rd line of code. The earlier object in heap String("Java") will become ready for garbage collection.
Java is not similar to c in case of strings it creates a new object instead of modifying the existing objects. This is cause strings in java are immutable.
String s1=new String("Java"); /* 2 objects created as 'new' is used - s1 (holds reference to new String) and string literal "Java" */
String s2="Tech"; /* 3rd Object - "Tech", s2 just holds reference to it */
s1+=s2; /* 4th Object created, which is concatenation of s1 and s2. s1 holds reference to it.
So total 4 objects created.
From my understanding of Java, String is immutable. So the following will not concatenate and only give me the output app, proving it is immutable. I get that.
String apple = new String("app");
apple.concat("le");
System.out.println(apple);
But I am able to change the value of the String after initializing it with some value. Isn't this considered immutable anyway?
String orange = "ora";
orange = "orange";
System.out.println(orange);
The Object is immutable, the reference is not. You can change the reference as often as you like with orange = "Orange" but you are not changing the object. You are merely letting go of the old one and attaching the reference to the new one.
When you do:
orange = "orange";
what happens behind the scenes is:
orange = new String("orange");
That is, orange, as a reference to a String, is modified. It just points to a different String instance.
In this statement:
apple.concat("le");
what happens is that you create a new String object which is the result of apple.concat(new String("le")), but you don't assign it...
But then again you are dealing with strings here; strings are one of the few classes in Java which have built-in behaviors, such as:
final String x = "a" + "b";
which in fact translates to:
final String x = new StringBuilder("a").append("b").toString();
You have stepped into a hornet's nest.
Instances of the String class are immutable. The apple variable is not immutable, but it would be if you declared it final.
For example, the following code is mutating the object:
Person p = new Person("John");
p.setName("Jenny"); // <-- mutating
Immutable objects (like String, Integer, ...) have no method that change the state of the object.
In contrast, the following code is changing the value of p, but is not mutating any objects:
Person p = new Person("John");
p = new Person("Jenny");
p is simply updated to reference a different Person object. The original "John" object still exists (until garbage collected).
Now, if p was defined as final, then it (the variable) would be immutable too:
final Person p = new Person("John");
// Cannot: p = new Person("Jenny");
In your particular case, concat does not mutate the String, it creates a new string and returns it, so you need to:
String apple = new String("app");
apple = apple.concat("le");
System.out.println(apple); // prints "apple"
Here the variable is updated, but not the String object.
According to Wikipedia, an immutable object is:
an object whose state cannot be modified after it is created.
However, you are not modifying the original orange String object ("ora"): you are creating a new String object ("orange"), and this new object is being assigned to a variable.
Easy as cake
If that doesn't make sense, think of it this way. Supposing some Object was a block of chocolate cake, you can add icing or cut out parts of this cake without actually changing the identity of the cake. However, if you wanted to change it to a red velvet cake, you have to make a new cake, because you cannot modify a chocolate cake to make it into a red velvet cake (for practical purposes) the original. An immutable object means you cannot cut, or ice... that "cake", but you can replace it with a new cake.
orange = "orange" only means that orange is pointing to a new String instance instead of the old one ("ora").
Immutability means that you cannot change an object's state once it has been created. You haven't changed the state of the string instance that orange is referring to; you just made it refer to a new instance. Changing an object's state requires you to either call a method on that object that changes its state, or modify one of its publicly-accessible properties.
You're also confusing immutability of objects with immutability of references. To make a reference immutable (i.e., make sure you cannot make it point to something else once it has been initialized) you use the final keyword.
So if you had:
final String orange = "ora";
orange = "orange";
You would now get an error because the reference is immutable and cannot be reassigned.
The Object is immutable while the reference is not. You can change the reference but not object.
Adding an example to make us more clear
String orange1 = "ora";
String orange2 = orange1;
System.out.println("orange1: " + orange1 + " , orange2: " + orange2);
System.out.println("----------------------");
orange2 = "orange";
System.out.println("orange1: " + orange1 + " , orange2: " + orange2);
So my question is in relation to declaring and assigning strings.
The way I usually declare strings is by doing the following:
String s1 = "Stackoverflow";
And then if I ever need to change the value of s1 I would do the following:
s1 = "new value";
Today I found another way of doing it and declaring a string would go like:
String s2 = new String("Stackoverflow");
And then changing the value would be:
s2 = new String("new value");
My question is what is the difference between the two or is it simply preferential. From looking at the code the fourth line
s2 = new String ("new value");
I'm assuming that doing that would create a new memory location and s2 would then point to it so I doubt it would be used to change the value but I can see it being used when declaring a string.
From the javadoc :
Initializes a newly created String object so that it represents the
same sequence of characters as the argument; in other words, the newly
created string is a copy of the argument string. Unless an explicit
copy of original is needed, use of this constructor is unnecessary
since Strings are immutable.
So no, you have no reason not to use the simple literal.
Simply do
String s1 = "Stackoverflow";
Historically, this constructor was mainly used to get a lighter copy of a string obtained by splitting a bigger one (see this question). Now, There's no normal reason to use it.
String s1 = "Stackoverflow"; // declaring & initializing s1
String s2 = new String("Stackoverflow"); // declaring & initializing s2
in above cases you are declaring & initializing String object.
The difference between
//first case
String s2 = new String("new String"); // declaring & initializing s2 with new memory
// second case
s2 = "new String" // overwriting previous value of s2
is in the first case you are creating a new object, i-e; allocating memory for a new object which will be refrenced by s2. The previous address to which s2 was pointing/referencing hasn't released the memory yet which will be gc when the program ends or when system needs to.
The good programming practice (second case) is to initialize an object once, and if you want to change its value either assign null to it and then allocate new memory to it or in case of string you can do like this
s2= "new String";
String s1 = "Stackoverflow";
This line will create a new object in the String pool if it does not exist already. That means first it will first try searching for "Stackoverflow" in the String pool, if found then s1 will start pointing to it, if not found then it will create a new object and s1 will refer to it.
String s2 = new String("Stackoverflow");
Will always create a new String object, no matter if the value already exists in the String pool. So the object in the heap would then have the value "Stackovrflow" and s2 will start pointing to it.
s2 = new String("new value");
This will again create a new Object and s2 will start pointing to it. The earlier object that s2 was pointing to is not open for garbage collection (gc).
Let me know if this helps.
The main difference is that the constructor always creates a totally new instance of String containing the same characters than the original String.
String s1 = "Stackoverflow";
String s2 = "Stackoverflow";
Then s1 == s2 will return true
String s1 = "Stackoverflow";
String s2 = new String("Stackoverflow");
Then s1 == s2 will return false
Just using the double quotes option is often better:
With a constructors you might create two instance of String.
Easier to read and less confusing
#user2612619 here i want to say is .. when ever ur creating object with "new" operator it always falls in heap memory . so wenever u have same content but different objects than also it will create new objects on heap by this u cant save memory ....
but in order to save memory java people brought concept of immutable where we can save memory .. if u r creating a different object with same content .. string will recognize dat difference and creates only one object with same content and points the two references to only one object ..
i can solve ur doubts from this figure ..
case 1:
String s = new String("stackoverflow");
String s1 = new String("stackoverflow");
as they are two different objects on heap memory with two different values of hashcode .. so s==s1 (is reference comparison) it is false .. but s.equals(s1) is content comparison ..so it is true
case 2:
String s = "stackoverflow";
String s1 = "stackoverflow";
here objects fall in scp(string constant pool memory)
same object for two different refernces .. so hashcode also same .. same reference value .. so s==s1 is true here [u can observe from figure clearly]
s.equals(s1) is true as content comparison.. this is very beautiful concept .. u will love it wen u solve some problems ... all d best
Creating String object Directly:
String s1 = "Hip Hop"
will create a string object but first JVM checks the String constant or literal pool and if the string does not exist, it creates a new String object “Hip jop” and a reference is maintained in the pool. The variable s1 also refers the same object. Now, if we put a statement after this:
String s2 = "Hip Hop"
JVM checks the String constant pool first and since the string already exists, a reference to the pooled instance is returned to s2.
System.out.println(s1==s2) // comparing reference and it will print true
java can make this optimization since strings are immutable and can be shared without fear of data corruption.
Creating String Object using new
String s3 = new String("Hip Hop")
For new keyword, a String object is created in the heap memory wither or not an equal string object already exists in the pool and s3 will refer to the newly created one.
System.out.println(s3==s2) // two reference is different, will print false
String objects created with the new operator do not refer to objects in the string pool but can be made to using String’s intern() method. The java.lang.String.intern() returns an interned String, that is, one that has an entry in the global String literal pool. If the String is not already in the global String literal pool, then it will be added to the pool.
String s4 = s3.intern();
Systen.out.println(s4 == s2); // will print `true` because s4 is interned,
//it now have the same reference to "Hip Hop" as s2 or s1
But try:
Systen.out.println(s4 == s3) // it will be false,
As the reference of s4, s2 and s1 is the reference to the pooled instance while s3 is referring to the created object in heap memory.
use of new for creting string:
prior to OpenJDK 7, Update 6, Java String.susbtring method had potential memory leak. substring method would build a new String object keeping a reference to the whole char array, to avoid copying it. You could thus inadvertently keep a reference to a very big character array with just a one character string. If we want to have minimal strings after substring, we use the constructor taking another string :
String s2 = new String(s1.substring(0,1));
The issue is resolved in JDK 7 update 6. So No need to create string with new any more for taking advantage provided by String literal pool mechanism.
Referance:
String literal pool
using new to prevent memory leak for using substring
If
String x = "abc";
String y = "abc";
What is the memory allocation for x and y ?
The two variables will each take as much space as is required for a reference.
The two references will both have the same value - that is, they'll refer to the same object - due to interning of string literals. In other words, there will only be one String object. However many times you execute this piece of code (within the same classloader, at least) the values of x and y will always refer to the same single object.
The two variables are still independent, of course - you can change one without changing the other:
String x = "abc";
String y = "abc";
x = "def";
System.out.println(y); // Still prints abc
Here is a nice reference regarding string literals in Java. I guess you are interested in this quotation:
If String objects having the same data
are created using a constant
expression, a string literal, a
reference to an existing string, or by
explicitly using the intern() method,
their references will be the same.
There is only one string which be placed in the String literal pool. No matter how many times you run these two lines e.g in a loop, not more objects will be allocated.
EDIT: If you want to create more objects you can do this.
String x = new String("abc"); // don't do this
String y = new String("xyz"); // don't do this either.
This creates an object every time because you told it to. ;)
String x = "abc"; it will create one string object and one reference variable. "abc" will go into the pool and x will refer to it.
Because strings are most commonly used. So Java uses memory optimization and to prevent excessive usage of memory it uses string pool memory in which if a string object with the same value is already present then the new object reference created with the same string value will point towards the same. But if the string is created using "new" then the object is created in heap memory and also in string pool if the same string value is not already present in it. To understand more differences and how the memory is allocated go through the code snippet.
String s1="hello"; // here s1 is string object reference, "hello" is string
// value of string object created using this statement
String s2="hello"; // s2 reference the same string object as s1 do in string
// pool area
String s3=new String("hello"); // string object created in heap memory
String s4=new String("hello"); // new string object created in heap memory
System.out.println(s1==s2); //true as both string object references point
// towards same object in string pool area
System.out.println(s3==s4); //false as both string objects reference to two
//different object having same string value in heap area
String s5="hell"+"o";
System.out.println(s1==s5); //true as s5 is a combination of two strings
String s6="hell";
String s7=s6+"o"; // when we use already initialised string object reference,
// then new object created in heap memory
System.out.println(s1==s7); //false
s6+="o"; //when we use already initialised string object reference, then new
//object created in heap memory
System.out.println(s1==s6); //false
System.out.println(s3==s6); //false as objects in heap memory are not comparable
//even if with same string value using "==" so use
//equals() function
s6="hello";
s4="hello"; // initially s4 was created using "new" so points string in heap
// area now it points towards string pool area
System.out.println(s1==s6); //true s6 is reinitialized withou using new so
//reference the string in string pool area which is
//common for all objects with same string value
System.out.println(s3==s6); //false again one object(s3) reference string object
//in heap area and s6 reference string object in
//string pool
System.out.println(s3=="hello"); // false as s3 reference string object in heap
// area so not comparable
System.out.println(s1=="hello"); // true
String s8="";
s8+="hello";
System.out.println(s1==s8); //false
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
System.out.println(abc[0]);
by changing "def" object, my abc object is changed as well. Beside String[] array has this characteristic what other java object has similar characteristic? can explain more? in order to prevent abc from changed when i changed def, i will have to do def = abc.clone();
You are confusing object mutability/immutability with copying of reference values.
In these diagrams, [var/index] is a reference variable, and {{an Object}} is an object.
String abc[]={"abc"};
String def[]={};
[abc] ------> {{a String[1]}}
[0] --------------> {{a String "abc"}}
[def] ------> {{a String[0]}}
Now you make def reference variable points to the same object as abc reference variable:
def=abc;
[abc] ------> {{a String[1]}}
/ [0] --------------> {{a String "abc"}}
/
[def] ---/ {{a String[0]}}
At this point, the array of length zero is unreferenced, and should be garbage-collectable. We can narrow our discussion to the array of length one. Note that a String[] is an array of references. With this next line, you changed what the only element in the length one array points to.
def[0]=def[0]+"changed";
[abc] ------> {{a String[1]}}
/ [0] ---------\ {{a String "abc"}}
/ \
[def] ---/ \--> {{a String "abcchanged"}}
Note that {{a String "abc"}} itself was not mutated. [abc] and [def] now points to the same {{a String[1]}}, which is mutable (i.e. you can make the elements of the array, which are references to String objects, to point to anything).
in order to prevent abc from changed when i changed def, i will have to do def = abc.clone();
Actually, that's not quite accurate. Let's see what happens if you clone() an array of references to a mutable type StringBuilder.
StringBuilder[] abc = new StringBuilder[] { new StringBuilder("Hello") };
StringBuilder[] def = abc.clone();
def[0].append(" world!");
System.out.println(abc[0]); // prints "Hello world!"
I won't make the diagrams for you this time, but you can easily draw it out on paper. What's happening here is that even though clone() makes a second {{a StringBuilder[1]}} object with its own element (i.e. def != abc), that element is pointing to the same {{a StringBuilder}} object (i.e. def[0] == abc[0]).
In short:
Immutability means that objects of a certain type can not change in any meaningful way to outside observers
Integer, String, etc are immutable
Generally all value types should be
Array objects are mutable
It may be an array of references to immutable types, but the array itself is mutable
Meaning you can set those references to anything you want
Also true for array of primitives
An immutable array will not be practical
References to objects can be shared
If the object is mutable, mutation will be seen through all these references
If you want more in-depth understanding of the issues, I recommend the following:
Is Java pass by reference? -- NO!
Are Java function parameters always passed-by-value? -- YES!
Immutable objects are objects that cannot be changed once created. String is an obvious example. Arrays are mutable. If you want an immutable collection, use a List instead:
List<String> abc = Collections.unmodifiableList(
Arrays.asList("abc")
);
Mutable objects have mutators. A mutator is any method that modifies the state of the object. Setters are an obvious example. A typical immutable object will look like this:
public class Person {
private final String firstName;
private final String lastName;
private final Date dateOfBirth;
public Person(String firstName, String lastName, Date dateOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.dateOfBirth = new Date(dateOfBirth.getTime());
}
public String getFirstName() { return firstName; }
public String getLastname() { return lastName; }
public Date getDateOfBirth() { return new Date(dateOfBirth.getTime()); }
}
Generally speaking, for immutable objects, all members are final and immutable. Date is a good example of the issue above. Date is not immutable, which many (myself included) consider a design mistake. As a result of it being mutable you have to do lots of defensive copying.
just to be pedantic, there's no "abc" object or "def" object. There's the single String[] that abc, and then def happen to refer to. That's why "both objects" changed. They were, in fact, referring to the same object.
In simple terms it is like this :-
Lets assume Sample to be a class then,
Sample sam1 = new Sample();
will clearly be explained as sam1 being the reference to the object created.
but
Sample sam2;
just declares sam2 to be a reference variable of Sample type and has no object of Sample class being pointed by it.
now if we do this operation
sam2 = sam1;
then it means both the reference variables point to the same object and now one can refer to that object using any one of the two references.
Obviously one can manipulate the fields employing the valid methods using either of the references.
And this is what has been done here too.
String abc[]={"abc"};
String def[]={};
def=abc;
def[0]=def[0]+"changed";
and so changing def[0] changes abc[0] too.
Now when you clone you are creating a clone of the existent object.
The clone and the cloned objects independently exist
as 2 different objects and so the result of manipulations on one
is not reflected as you stated.
In java, you can always change the elements in an array, regardless of the type of the array. Consider making a separate copy of the data in order to protect the initial value of abc if you would like to keep the data in an array structure:
String abc[]={"abc"};
String def[];
def = Arrays.copyOf(abc, abc.length);
Alternatively, use cletus solution:
List abc = Collections.unmodifiableList(
Arrays.asList("abc")
);