Objects and Strings equality and memory digrams - java

I have having a bit of trouble understanding the difference between these two:
Suppose we have:
String x = "Test";
String y = x;
y = "Not Test"; //x is not modified here
The memory diagram for these two steps is the following:
x-> "Test"
x-> "Test" <-y
x-> "Test" y-> "Not Test"
But, consider class A with field 'int var':
A a = new A();
A b = a;
b.var = 5;
Here, if we modify b.var, a.var also changes to 5. Why is this different from the above case with strings?
Additionally, I would appreciate it if someone wouldn't mind explaining these memory diagrams for strings and objects. Would the result be different if a and b were objects of different classes set equal? Thanks.

There's a difference between
b.var = 5;
and
b = new A();
The second statement is similar to what you do in your first snippet, since y = "Not Test"; makes y refer to a new instance.
The first statement updates the state of the instance referred by both a and b, so both are affected.
Here's a diagram that shows your second snippet :
a -> object of class A <- b
containing an int
variable `var`
var <- 5
Both a.var and b.var contain 5, since they are the same variable.

Because String is Immutable class, state of which class can not be changed. While A is mutable because you changed it's state by changing value of variable. Secondly, both a and b are referencing to the same memory location and changing state of one will get reflected in second one but that's not the case in case of String if String a and b is Test changing a to Test1 will not change the Test to Test1 but it will create new String Test1 and assign it to a.

In the second case they are both pointing at the same place in the memory.
A a = new A(); a-->[MEMORY SPOT NR1]
A b = a; a-->[MEMORY SPOT NR1] AND b-->[MEMORY SPOT NR1]
b.var = 5; a-->[MEMORY SPOT NR1] AND b-->[MEMORY SPOT NR1]
and the value in var in [MEMORY SPOT NR1] is 5,
so both a.var and b.var take the value 5

Related

Change in Integer value creates new instance [duplicate]

I know this is probably very stupid, but a lot of places claim that the Integer class in Java is immutable, yet the following code:
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
Executes without any trouble giving the (expected) result 6. So effectively the value of a has changed. Doesn't that mean Integer is mutable?
Secondary question and a little offtopic: "Immutable classes do not need copy constructors". Anyone care to explain why?
Immutable does not mean that a can never equal another value. For example, String is immutable too, but I can still do this:
String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"
str was not changed, rather str is now a completely newly instantiated object, just as your Integer is. So the value of a did not mutate, but it was replaced with a completely new object, i.e. new Integer(6).
a is a "reference" to some Integer(3), your shorthand a+=b really means do this:
a = new Integer(3 + 3)
So no, Integers are not mutable, but the variables that point to them are*.
*It's possible to have immutable variables, these are denoted by the keyword final, which means that the reference may not change.
final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.
You can determine that the object has changed using System.identityHashCode() (A better way is to use plain == however its not as obvious that the reference rather than the value has changed)
Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
prints
before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda
You can see the underlying "id" of the object a refers to has changed.
To the initial question asked,
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
Integer is immutable, so what has happened above is 'a' has changed to a new reference of value 6. The initial value 3 is left with no reference in the memory (it has not been changed), so it can be garbage collected.
If this happens to a String, it will keep in the pool (in PermGen space) for longer period than the Integers as it expects to have references.
Yes Integer is immutable.
A is a reference which points to an object. When you run a += 3, that reassigns A to reference a new Integer object, with a different value.
You never modified the original object, rather you pointed the reference to a different object.
Read about the difference between objects and references here.
Immutable does not mean that you cannot change value for a variable. It just means that any new assignment creates a new object ( assigns it a new memory location) and then the value gets assigned to it.
To understand this for yourself, perform Integer assignment in a loop ( with integer declared outside the loop ) and look at the live objects in memory.
The reason why copy constructor is not needed for immutable objects is simple common sense. Since each assignment creates a new object, the language technically creates a copy already, so you do not have to create another copy.
This is how I understand immutable
int a=3;
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8
If int could mutate, "a" would print 8 but it does not because it is immutable, thats why it is 3. Your example is just a new assignment.
"Immutable classes do not need copy constructors". Anyone care to explain why?
The reason is that there is rarely any need to copy (or even any point in copying) an instance of a immutable class. The copy of the object should be "the same as" the original, and if it is the same, there should be no need to create it.
There are some underlying assumptions though:
It assumes that your application does not place any meaning on the object identity of instances of the class.
It assumes that the class has overloaded equals and hashCode so that a copy of an instance would be "the same as" the original ... according to these methods.
Either or both of those assumptions could be false, and that might warrant the addition of a copy constructor.
I can make clear that Integer (and other of its creed like Float, Short etc) are immutable by simple sample code:
Sample Code
public class Test{
public static void main(String... args){
Integer i = 100;
StringBuilder sb = new StringBuilder("Hi");
Test c = new Test();
c.doInteger(i);
c.doStringBuilder(sb);
System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
}
private void doInteger(Integer i){
i=1000;
}
private void doStringBuilder(StringBuilder sb){
sb.append(" there");
}
}
Actual Result
The result comes to he Hi There 100 instead of expected result (in case of both sb and i being mutable objects) Hi There 1000
This shows the object created by i in main is not modified, whereas the sb is modified.
So StringBuilder demonstrated mutable behavior but not Integer.
So Integer is Immutable. Hence Proved
Another code without only Integer:
public class Test{
public static void main(String... args){
Integer i = 100;
Test c = new Test();
c.doInteger(i);
System.out.println(i); //Expected result is 1000 in case Integer is mutable
}
private void doInteger(Integer i){
i=1000;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1="Hi";
String s2=s1;
s1="Bye";
System.out.println(s2); //Hi (if String was mutable output would be: Bye)
System.out.println(s1); //Bye
Integer i=1000;
Integer i2=i;
i=5000;
System.out.println(i2); // 1000
System.out.println(i); // 5000
int j=1000;
int j2=j;
j=5000;
System.out.println(j2); // 1000
System.out.println(j); // 5000
char c='a';
char b=c;
c='d';
System.out.println(c); // d
System.out.println(b); // a
}
Output is :
Hi
Bye
1000
5000
1000
5000
d
a
So char is mutable , String Integer and int are immutable.
Copy and run this code,I hope this will answer all your doubts
private static void wrapperClassDemo() {
//checking wrapper class immutability using valueOf method
//We can create wrapper class by using either "new" keyword or using a static method "valueOf()"
//The below Example clarifies the immutability concept of wrapper class in detail
//For better understanding just ciopy the below code to the editor and run
Integer num1 =Integer.valueOf(34); // i'm passing the 34 as the parameter to the valueOf method
System.out.println("value assigned to num1 is : "+num1);
System.out.println("Printing the hashcode assigned to store the \" num1 \"value in memory: "+System.identityHashCode(num1));
Integer num2 =Integer.valueOf(34);
System.out.println("value assigned to num2 is : "+num2);
System.out.println("Printing the hashcode assigned to store the \" num2 \"value in memory: "+System.identityHashCode(num2));
/*Now u can notice both the hashcode value of num1 and num2 are same. that is because once you created the num1 with the value 34 an object is
* created in the heap memory. And now You are passing the value same as num1 to the num2 .Now JVM Checks the same value is present in the heap Mmeomry
* If present the reference variable(in this example it is num2) will be pointed to the same address where the object num1 is stored so u get the same hashcode */
num2++; // You can use num2 = 35 as both are same;
System.out.println("\nvalue assigned to num2 is : "+num2);
System.out.println("Printing the hashcode of \" num1 \": "+System.identityHashCode(num1) + "\nPrinting the hashcode of \" num2 \": "+System.identityHashCode(num2));
System.out.println("As now you can notice the hashcode has changed for num2 ,That is because now a new object is created for num2 and it is referencing the new object");
//Again i'm incrementing num2
System.out.println("\nBefore incremeting the hashcode of \" num2 \" is: "+System.identityHashCode(num2));
num2++; // You can use num2 = 36 as both are same;
System.out.println("After incremeting the hashcode of \" num2 \" is: "+System.identityHashCode(num2));
//now the hashcode value of num2 is changed ,again new object is created for the updated value and num2 is referencing new object ,and old object will be garbage collected
System.out.println("\n Thus the CONCLUSION is Wrapper objects are immutable ,They only create new object and refernce the new object ,They won't modify the present object ");
System.out.println("This is applicable for Strings also");
Something to hold in mind is that there is now a cache for Integer values. It sometimes saves developers from the mistake of using == instead of .equals() when changing from int to Integer. Not always though. When you instantiate a new Integer, there will be a new instance created. So Integers are not only immutable, but also semi static.
Integer a = 3;
Integer b = 3;
Integer c = new Integer(3);
b = b + 1;
b = b - 1;
System.out.println("a-id: " + System.identityHashCode(a));
System.out.println("b-id: " + System.identityHashCode(b));
System.out.println("c-id: " + System.identityHashCode(c));
System.out.println("a == b: " + (a == b));
System.out.println("a == c: " + (a == c));
System.out.println("a eq c: " + (a.equals(c)));
Gives the printout:
a-id: 666988784
b-id: 666988784
c-id: 1414644648
a == b: true
a == c: false
a eq c: true

Why does this code result in these answers?

I am currently learning Java, and I'm trying to understand the logic behind math in Java. On old tests in this course, there have been problems like the ones below. I am then supposed to write out what this code is going to display. My problem is that I don't understand two of the numbers in both codes.
In the first test class, the integer Tal prints out as 15. Ok, I can follow the logic there.
It goes like this:
c.setNbrOf(4+1) = 5
int tal = c.getNbrOf()+10 = 15
BUT
When I apply the same logic to the second test class I get the wrong answer.
My logic goes:
c.setNbrOf(4+1) = 5
c2.setNbrOf(5) +1 = 6
Since Customer c = c2, this means c also has the value of 6 (?)
So, int tal = 6 + 5 which is 11.
It's not though. When I run it, it's 12.
Why does the ++tal in the method andra affect its value globally? I thought it was only local.
I hope I haven't been to unclear.
The customer class is needed to run the test class.
public class Customer {
private String name;
private int nbrOf;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name=name;
}
public int getNbrOf() {
return this.nbrOf;
}
public void setNbrOf (int nbrOf) {
this.nbrOf=nbrOf;
}
}
The first test class.
public class Test {
public static void main(String[] args) {
Customer c = new Customer();
c.setName("Kund1");
c.setNbrOf(4+1);
int tal = c.getNbrOf()+10;
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf());
foo(c, tal+3);
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf());
System.out.println("Tal: "+tal);
}
public static void foo(Customer p, int x) {
p.setName("Kund2");
p.setNbrOf(x);
x ++;
}
}
The second.
public class Test {
public static void main(String[] args) {
Customer c = new Customer();
c.setName("K1");
Customer c2 = c;
c.setNbrOf(4+1);
c2.setNbrOf(c.getNbrOf()+1);
int tal = c.getNbrOf()+5;
System.out.println("Namn: "+c.getName()+" ålder: "+c2.getNbrOf());
andra(c, ++tal);
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf()+",
"Tal: "+tal);
}
public static void andra(Customer p, int tal) {
p.setName("K2");
tal=9;
p.setNbrOf(tal);
}
}
When you write ++tal, it means tal = tal + 1; then return the new value of tal as a result. Hence, when you pass ++tal to a function, you have run two commands.
Also, you should be aware that setting value of tal inside andra function, is local and not changed the value of tal outside the function. Hence, the final value of tal after calling andra(c, ++tal) would be 12.
[EDIT] Fixed the incorrect part about pass by value and clone()
You are asking two questions so let's attach each one separately.
A) What is the value of c and c2 at specific points in the code.
To answer this you need to realize that just saying 'c = c2' doesn't tell the full story. You first create two instances of the Customer object and store the references to them in c and c2 respectively. When you assign c = c2 you are making both variable store the reference to the same (single) instance of Customer; the other will get garbage collected. Now, it is possible to change the state of the remaining object through method calls to either c OR c2 because they both refer to the same instance.
This means that
c.setNbrOf(4+1); // AAA
c2.setNbrOf(c.getNbrOf()+1); // BBB
changes the value of the same nbrOf member variable twice, it just looks like they are separate because you have made c an alias of c2 (or vice versa depending on how you want to look at it). After line AAA c.nbrOf does equal 5; to calculate what happens in line BBB you need to break the line up into its parts. Calling c2.setNbrOf() with an argument that is actually an expression of the sum of two things, the result of a call to c.getNbrOf() and the numeric literal '1'. The call to c.getNbrOf() returns 5 and the expression adds 1 to it before passing the result, 6, to the call of c2.setNbrOf(). Since c and c2 are aliases of each other you will get a result of '6' when you call getNbrOf using either c or c2 simply because they both point to the same instance.
B) Why does the ++tal in the method andra affect it's value globally?
Well, it doesn't affect the value globally, it only looks that way because again, you have run into an expression used as an argument to a method.
andra(c, ++tal); // CCC
The call to andra() does not pass '++tal' into the method, it evaluates the expression first, which actually increments tal by 1 in the local scope and then evaluates the value of tal to determine the value to be sent to the method call. This means that, yes, tal was 11 before the line CCC but during the evaluation of the arguments the variable's value was changed to 12 before the call is made. So why does the code print '12' when you can clearly see that
public static void andra(Customer p, int tal) {
p.setName("K2");
tal=9; // DDD
p.setNbrOf(tal);
}
line DDD should result in the value of p.nbrOf being 9? Well, yes, the value of p.nbrOf does get changed to '9' in the line following DDD, just as p.name gets changed to "K2". This leads to your question of why the code prints '12' instead of '9'. This is because of another thing you have to consider and that is scope. The method andra() actually creates a new storage location named 'tal' that is not the same location as the variable with the same name in main(), that is andra() is hiding the name 'tal' so that when it changes the value of 'tal' to 9 it is only changing the local variable and not the variable with the same name in the calling code.
I have to say that this sample code is doing several things to trip you up, which also means it's doing its job to help you understand the different ways the language handles its symbol table that can be confusing. The sample code isn't making it any better by using tal as a local variable in the test code AND as a parameter name in the methods, that is a poor practice but was used here to make the exercise more difficult.
Try this code to see what is actually happening.
// actually Test3 would be a better name, but I'll leave that to you
public class Test {
public static void main(String[] args) {
Customer c = new Customer();
c.setName("K1");
Customer c2 = c;
c.setNbrOf(4+1);
c2.setNbrOf(c.getNbrOf()+1);
int tal = c.getNbrOf()+5;
int tal2 = ++tal;
System.out.println("Namn: "+c.getName()+" ålder: "+c2.getNbrOf()+" reference to c:"+ c);
andra(c, tal2);
System.out.println("Namn: "+c.getName()+" ålder: "+c.getNbrOf()+",
Tal: "+tal);
}
public static void andra(Customer p, int tal3) {
p.setName("K2");
tal3=9;
System.out.println("BEFORE - reference to p: "+p+" tal: "+tal3+" p.nbrOf:"+p.getNbrOf());
p.setNbrOf(tal3);
System.out.println("AFTER - reference to p: "+p+" tal: "+tal3+" p.nbrOf:"+p.getNbrOf());
}
}
This should show several things, the reference to p should be a different value than the reference held in c, using unique variable and parameter names should make it clearer about which variables are being evaluated or changed, and moving the ++tal expression to outside the method call should show how the variable is not being changed from within andra().
c = c2 - this line means that from now you want c to point to the same space in memory that holds c2. From now all changes in c or c2 will affect in the same change in the value of the other one (two different refferences point to the same object)
andra(c, ++tal);
is:
tal = tal + 1; //12
andra(c, tal);
andra(c, ++tal); is the same as:
tal = tal + 1;
andra(c, tal);
While andra(c, tal++); is similar to:
andra(c, tal);
tal = tal + 1;
The pre-increment and post-increment operators increment the value prior to (pre) or after (post) evaluating the expression. This is not a "local" vs "global" scope. It affects the scope of the variable that is within scope.
Also, in your andra method, you are explicitly setting tal = 9 so it ignores the passed argument.
since we actually only have one object here, we could ignore OO here and write it in plain math:
if c2 = c, then there is only one object, therefore only one NbrOf
c.setNbrOf(4+1);
NbrOf = 4 + 1 = 5
c2.setNbrOf(c.getNbrOf()+1);
NbrOf = NbrOf + 1 = 5 + 1 = 6
int tal = c.getNbrOf()+5;
int tal = NbrOf + 5 = 6 + 5 = 11;
andra(c, ++tal);
this increases tal by 1 and assigns that value to tal, its equivalent to
tal = tal + 1;
andra(c, tal);
however, the tal inside of andra(c, tal); is an copied value (all primitives are passed by copy, not by reference. So assigning tal=9 wont affect the outside tal! Rename it inside andra(c, tal); to make it easier to understand.
conclusion, tal = 12

which is faster, creating new variable vs reusing old variable?

which is faster creating new variable or reusing old one for java programming language?
example
case 1: creating
int x = 5;
int var = 1;
case 2: reusing old one
int x = 5;
x = 1;
"Which is faster?" is the wrong question. "Which is correct for the algorithm?" is the right question.
As a rule, you only reuse a variable if it needs to hold a new primitive value or point to a different object, because it is the variable that represents the current state. If the variable is reassigned to hold something that means something different, you should not do that but use a new variable.
So sum += item; is a valid reuse of the variable sum. But
foo = 42;
buyQuantity(foo);
...
foo = 23;
sendMessages(foo);
is not a valid reuse of foo.
A related but different question is whether you should reuse an object to hold new values. Not usually. For example:
Foo foo = new Foo();
for (int ix = 0; ix < MAX_ITERS; ++ix )
{
foo.clear();
foo.fill();
process(foo);
}
is worse than:
for (int ix = 0; ix < MAX_ITERS; ++ix )
{
Foo foo = new Foo();
foo.fill();
process(foo);
}
I did an small and simple test: Running a loop on a large (10 million) array and fill each element with a number.
Test1 : define a var before the loop and use that
Test2 : define a const inside the loop
To make the test as honest as possible, all other operations were removed.
Code
//#ts-nocheck
const maxInt = 10000000
// fill Array with a number
let A = [...Array(maxInt)].map(x => 10);
// Test 1 : Variable declared before
let x
console.time('test1')
B = A.map((a) => {
x = 3
return x
})
console.timeEnd('test1')
// Test 2 : Const variable declared in the Loop, every time
console.time('test2')
C = A.map((a) => {
const x = 3
return x
})
console.timeEnd('test2')
Test results
The test was run multiple times and on avarage (not calculated) the results were:
test1: 190.656ms
test2: 282.766ms
(Running on a Macbook with enough memory and normal CPU)
My careful conclusion: Creating a Const every time does have a slight performance impact.

Java uses call by value but weird behavior in case of StringBuffer

I am new to java technology, and may be it is a simple problem but I am confused like anything. I know that there is no concept of call by reference in java. It only uses call by value i.e. passing copy to another method
Kindly check the output of below code
public class Test {
public static void main(String[] args) {
StringBuffer a = new StringBuffer ("A");
StringBuffer b = new StringBuffer ("B");
System.out.println("Before Operate"+a + "," +b);
operate (a,b);
System.out.println(a + "," +b);
}
static void operate (StringBuffer x, StringBuffer y) {
x.append(y);
y = x.append("C");
y.append("D");
}
}
output of above code is :ABCD , B (Second Syso)
i am not sure why this is appending everything in a not in b.
I googled a lot but it only create confusion.So it would be great help if some one elaborate it completely.
Thanks in advance
P.S:-If this is already been asked at this forum kindly provide me a link,as i was not able to find it.
Yes, Java is always pass-by-value, but you need to be aware of what the value is. For objects, the value passed is the reference to the object, not the object itself. See Is Java "pass-by-reference" or "pass-by-value"? for a detailed explanation.
i am not sure why this is appending everything in a not in b.
Because this:
x.append(y);
y = x.append("C");
y.append("D");
is exactly the same as this:
x.append(y);
x.append("C");
x.append("D");
Since StringBuilder#append() returns this, so that assignment to y in
y = x.append("C");
overwrites the reference to the object which was passed in (b) with a reference to x (aka a).
when you do this:
y = x.append("C");
that all happend is just make x and y have the same reference (for x).
And all you did on y after that operation was just did on x.
So,At last all of the three operation just happend on x ,just like Matt Ball said:
x.append(y);
x.append("C");
x.append("D");
and x should be "ABCD",y should not be change.

final variable case in switch statement

final int a = 1;
final int b;
b = 2;
final int x = 0;
switch (x) {
case a:break; // ok
case b:break; // compiler error: Constant expression required
}
/* COMPILER RESULT:
constant expression required
case b:break;
^
1 error
*/
Why am I getting this sort of error? If I would have done final int b = 2, everything works.
The case in the switch statements should be constants at compile time. The command
final int b=2
assigns the value of 2 to b, right at the compile time. But the following command assigns the value of 2 to b at Runtime.
final int b;
b = 2;
Thus, the compiler complains, when it can't find a constant in one of the cases of the switch statement.
b may not have been initialized and it is possible to be assigned multiple values. In your example it is obviously initialized, but probably the compiler doesn't get to know that (and it can't). Imagine:
final int b;
if (something) {
b = 1;
} else {
b = 2;
}
The compiler needs a constant in the switch, but the value of b depends on some external variable.
The final variable without value assigned to it is called a blank variable. A blank final can only be assigned once and must be unassigned when an assignment occurs or once in the program.
In order to do this, a Java compiler runs a flow analysis to ensure that, for every assignment to a blank final variable, the variable is definitely unassigned before the assignment; otherwise a compile-time error occurs
That is why when the compiler compiles the switch construct it is throwing constant expression required because the value of b is unknown to the compiler.

Categories

Resources