Could somebody please explain how this program is executed?
Here is the code whose output I just can't quite seem to get it:
class Box {
int size;
Box (int s) {
size = s;
}
}
public class Laser {
public static void main(String[] args) {
Box b1 = new Box(5);
Box[] ba = go(b1, new Box(6));
ba[0] = b1;
for(Box b : ba)
System.out.println(b.size + " ");
}
static Box[] go (Box b1, Box b2) {
b1.size = 4;
Box[] ma = {b2, b1};
return ma;
}
}
The actual output when I run this is 4, 4. But according to my understanding this should be 5, 4.
Can anyone please help understand how this is being executed?
I have added the comments for you;
The important TWIST that you missed here is;
Box[] ma = {b2, b1}; its not {b1,b2}. Memory locations are interchanged while returning.
public static void main(String[] args) {
Box b1 = new Box(5); // b1 == location A
Box[] ba = go(b1, new Box(6)); // ba == location B which stores Location A, D
// PLEASE NOTE HERE
// After the function go() is executed;
// ba[] will have {D, A}
// So ba[0] will have object b1 which is at location A.
ba[0] = b1; // location B will now store A and A
for(Box b : ba)
System.out.println(b.size + " "); // Output: 4 and 4
}
static Box[] go (Box b1, Box b2) { // go(location A, location D )
b1.size = 4; // A's object.size = 4
Box[] ma = {b2, b1}; // position is interchanged here (D and A)
return ma; // return the location of ma
}
Hope this helps.
Do let me know if you have any questions. Everything is pass by value in java. The memory addresses are passed by value.
When you pass an object as a parameter, you're actually passing a copy of a reference to it. That is, if you modify the parameter object inside the method, the object will retain those modifications when that method returns, which is why you see b1 retaining the size = 4 assignment after go returns.
Java always passes references to objects in method calls. When you're calling go, the first argument (b1), is a reference to the same b1 Box that you have in your main. You then modify that object, whose size is now 4.
The values passed to go are references to the objects. If you're coming from C, you can think of the parameters as having pointer types, something like
Box** go (Box *b1, Box *b2) {
b1->size = 4;
/* allocate an array of Box*, set it up, return it */
}
(Sorry if I got the C syntax wrong.) The pointers (references) themselves are passed by value, which means that if you say inside "go" (in the C program):
b1 = &some_other_box;
it doesn't affect any variables on the calling side, and it works the same way in Java. This makes it a bit different than a var parameter in PHP or Pascal.
Java passes copies of references to objects in method calls.
You can't change an object by assigning to it.
public static void main(String[] args) {
Box b1 = new Box(5);
Change(b1);
System.out.println(b1.size + " ");
static void Change(Box b1) {
b1 = new Box(6);
}
This will always return 5, because the function Change only overwrites the copy to the referenced object.
You can however affect the object's properties like so:
public static void main(String[] args) {
Box b1 = new Box(5);
Change(b1);
System.out.println(b1.size + " ");
static void Change(Box b1) {
b1.size = 6;
}
This will return 6 (the reference to the object remains unchanged).
If the function 'go' in the original post is in C (and b1 and b2 are C pointers), it can do the following two things (which the caller will see):
Change the value of variables in the data structures pointed to by b1 and b2.
Make the original b1 and b2 point to different data structures.
In Java, we can do 1 but NOT 2, since go does not have access to the original b1 and b2. (It has access to copies of b1 and b2. At the beginning of the subroutine, the copy b1 points to the same object as the original b1 and so on.)
Saying Java is pass by call DOES miss something, namely the ability of the function to do 1, i.e., change the properties of the object in the heap referenced by b1 and b2. [This is what happens in the statement, b1.size = 4;, which caused the original poster's confusion.]
b1 in 'go' is NOT the same location as b1 in 'main'. However, when the function starts, b1 in 'go' references the same object as b1 in 'main' and any changes made to the object using b1 in 'go' will be seen when b1 in 'main' is used as the reference.
However, if b1 in 'go' is set to another Box, b1 in 'main' will NOT see this; it will still see the previous Box.
In Java, objects are passed by reference, primitives are passed by value.
public class Laser {
public static void main(String[] args) {
//Create a Box of size 5.
Box b1 = new Box(5);
//Create an array of Box objects, which are the results of the go method
Box[] ba = go(b1, new Box(6));
// ba now looks like {new Box(6), b1 /*b1 is size 4 now*/}
// assign reference to b1 at index 0 in ba.
ba[0] = b1;
// array now looks like {b1, b1}
for(Box b : ba)
System.out.println(b.size + " ");
}
static Box[] go (Box b1, Box b2) {
//set the size of the first box to 4
b1.size = 4;
//create an array of boxes, with b2 in index 0 and b1 in index 1
Box[] ma = {b2, b1};
return ma;
}
}
Related
I am new to Java.
I tired the following java code
public class A {
int x;
public static void main(String[] args) {
A a1= new A();
a1.setX(5);
A a2=a1;
System.out.println(a1.getX());
System.out.println(a2.getX());
a2.setX(10);
System.out.println(a1.getX());
System.out.println(a2.getX());
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
I thought the output will be
5
5
5
10
But when I compile and run the code the output is coming as
5
5
10
10
Why the a1 x value is changing with a2 x?
A a2=a1;
This statement causes the a2 variable to represent the same location in memory that a1 represents. Therefore, any changes you make to the object at this memory location are changing the same pieces of memory as if you had been making those changes to a1.
If you want a2 to point to a different memory location, you'll need to allocate memory to hold the new value, like you did with a1:
A a2 = new A();
Objects in java are defined by reference. this means that when you do a2 = a1 what it means that a2 points to the same instance as a1. this means that changing one changes the other as well
You've declared an object called a1. and set it's value to 5. so its name = a1, value = 5. Let's pretend the address of a1 is 0x123.
Then you've declared an object called a2, and told it it has the same address as a1. when you said a2 = a1. Therefore whatever is in a1 (to start with, 5) will be pointed to by a2 also. And the address of a1 and a2 is, in both cases, 0x123.
Then you set the value in a2 to 10. In other words the value at address 0x123 will be 10. but a1 also has the address 0x123, so it doesn't matter whether you print a1 or a2, they both point to the value 10 that is in the same memory location at 0x123.
It's like the value is in a box which happens to have two different names on it, but it's still the same box with the same address and therefore with the same content.
I hope that helps.
I would like to understand how primitive and object reference variable behaves differently. I have used the below code from OCA/OCP Java SE7 by Kathy Sierra as an example:
public class VariableTesting {
public static void main(String[] args) {
int a = 10;
System.out.println("a= " + a);
int b = a;
b = 30;
System.out.println("a= " + a + " after change it to b and b is " + b);
Dimension a1 = new Dimension(5, 10);
System.out.println("a1.height = " + a1.height);
Dimension b1 = a1;
b1.height = 30;
System.out.println("a1.height= " + a1.height + " after change to b1");
}
}
In the above piece of code, I'm getting the value of a = 10; before and after changing the value of b.
The output for the primitive variable case is:
a = 10
a = 10 after change it to b and b is 30
However, in object reference variable I'm getting a different value once I change the value of b1.height = 30;
The output for the reference variable case is:
a1.height = 10
a1.height = 30 after change to b1
It is mentioned in the book that in both case the bit pattern is copied and a new copy is placed. If this is true, then why we are getting different behavior?
This is the underpinning difference between a reference and a primitive. In both cases, you're getting the actual value, but only in the case of an object do you have a chance to impact the result of any other usages of it.
Let's walk through the code.
int a = 10;
int b = a;
These two declarations are saying the following:
Assign the value 10 to an int identifier called a.
Assign the value of a to an int identifier called b.
So far, so good. Nowhere do we say that a is referenced by b; we're only taking values.
If we declare:
b = 30;
We're saying take the value of 30 and assign it to the identifier b.
We don't do anything with a at that point; it already contains the value 10. This is why a and b are different.
Now, when we get to the object, things don't really change on the surface...
Dimension a1 = new Dimension(5, 10);
Dimension b1 = a1;
We translate this as:
Assign the value of instantiation of a new Dimension with (int) parameters 5 and 10 to a Dimension identifier a1.
Assign the value of a1 to a Dimension identifier b1.
We're still assigning values here, since Java is pass-by-value. The kicker here is that in Java, the value of an object is still a reference to that object.
By the above example, a1 and b1 are pointing to the same instance.
Now, when we state this:
b1.height = 30;
We're actually saying:
Assign the value 30 to the field height dereferenced through the value b1.
We're still referring to the value of b1 here, which is tied to a1. This is why you see the difference; because a1 and b1 refer to the same value (which is the same reference), any change done through the identifier b1 is reflected through a1.
There is only one instance
When you say
Dimension b1= a1; // <-- assigns reference of a1 to b1.
you assign the reference address that a1 refers to to b1. Thus, when you modify the height field through b1 you also modify a1.
b1.height=30; // <-- a1.height = 30
Create another instance
If you want b1 to be a unique referene, then you use new.
Dimension b1= new Dimension(a1.width, a1.height); // <-- creates a new Dimension
So I've got this piece of code,
package test1;
class Student13
{
public static void main(String [] args)
{
Student13 p = new Student13();
p.start();
}
void start()
{
long [] a1 = {3,4,5};
long [] a2 = fix(a1);
System.out.print(a1[0] + a1[1] + a1[2] + " ");
System.out.println(a2[0] + a2[1] + a2[2]);
}
long [] fix(long [] a3)
{
a3[1] = 7;
return a3;
}
}
Can you tell me why it returns 15 15 and not 12 15? Function fix is applied only for long[] a2, so how come that the final result is 15 15?
You pass the a1 array to fix(), which is called a3 in the fix() method, but is regardless still referencing a1. So when you update a3: a3[1]=7, you actually update the paramater value of fix() which was a1. Thus you updated a1!
In the line
long a1[] = { ... };
you are creating one array object. This will be the only one throughout the rest of the program.
Now the call to
fix(a1);
assigns a reference to exactly that array to the parameter a3 in this fix method. As this method returns this reference (return a3;), the line
long[] a2 = fix(a1);
will assign the same reference to the variable a2. So at all points, all variables and parameters referred to the same array.
The fix method is modifying that array. So the modification is seen by all aliases you have.
Reference of a1[] is passed as a parameter to fix() that's why basically
a1[] == a2[] after calling fix().
a2[] is pointing to a1[] but a1[] sum is now 15, so a2[] sum is also 15.
This was a question on an exam. Luckily I picked the right answer, but I still can't see why it's right.
Consider this program:
class D {
protected C c;
public D(C c) {
this.c = new C(c);
}
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
}
class C {
protected String s;
public C(String s) {
this.s = s;
}
public C(C c) {
this(c.s);
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public static void main(String[] args) {
C c1 = new C("1");
C c2 = new C("2");
D[] d = {
new D(c1), new D(c1), new D(c2), new D(c2)
};
d[0] = d[3];
c1.setS("3");
String r = "";
for (D i: d) {
r += i.getC().getS();
}
System.out.println(r);
}
}
It'll print 2122. I would expect 2322 however (I'm clearly wrong when you run the code). My reasoning behind that:
In the third line of the main method, four instances of D get initialized.
The constructor of D makes a new instance of C. An instance of C has a String variable which points somewhere to a spot in the memory. Now the instance variable c, let's call it c3, of the object in d[1] has a instance variable (type String), let's call it s3, pointing to the same memory as the String s1, variable of c1.
So when we change s1, I'd expect the value of s3 also to change, since it's pointing to the same spot in the memory.
On a side note, if you change the constructor of D, see below, you'll get 2322 instead. Which I'd expect, since now the variable c3 in d[1] is pointing directly towards the memory location of c1.
public D(C c) {
this.c = c;
}
My thoughts so far on the explanation (could be wrong):
When initializing the instance variable s1/s3, new String objects get made (so far I assumed they were pointing towards "1" in the String pool, since the constructor of C makes it look that way)
When changing s1, it's pointer will be redirected towards "3" in the String pool. Rather than "1" becoming "3" in the pool.
Could anyone explain this behaviour? What are the errors in my (faulty) reasoning?
This is not related to String pooling at all. Main answer: Is Java "pass-by-reference" or "pass-by-value"?
That's because D creates a new instance of C based on C#c. This mean that the instance of D#c is not the same instance as parameter C passed in constructor D, thus modifying that instance won't affect the current instance in D#c.
Re explaining all this in nice terms.
Here's what you're testing:
class Surprise {
String item;
public Surprise(String item) {
this.item = item;
}
//this is called copy constructor
//because you receive an object from the same class
//and copy the values of the fields into the current instance
//this way you can have a "copy" of the object sent as parameter
//and these two object references are not tied by any mean
public Surprise(Surprise another) {
//here you just copy the value of the object reference of another#item
//into this#item
this.item = another.item;
}
}
class Box {
Surprise surprise;
public Box(Surprise surprise) {
//here you create a totally new instance of Surprise
//that is not tied to the parameter surprise by any mean
this.surprise = new Surprise(surprise);
}
public static void main(String[] args) {
Surprise surprise1 = new Surprise("1");
Surprise surprise2 = new Surprise("2");
Box[] boxes = {
new Box(surprise1),
new Box(surprise1),
new Box(surprise2),
new Box(surprise2)
};
boxes[0] = boxes[3];
//you update surprise1 state
//but the state of Box#surprise in the boxes that used surprise1
//won't get affected because it is not the same object reference
surprise1.item = "3";
//print everything...
System.out.println("Boxes full of surprises");
//this code does the same as the printing above
for (Box box : boxes) {
System.out.print(box.surprise.item);
}
System.out.println();
}
}
After testing the code (see below), I found out that I don't understand some fundamentals.
Class A.
class A {
private String s;
private int[] array;
private B b;
public A(String s, int[] array, B b) {
this.s = s;
this.array = array;
this.b = b;
}
}
Class B.
class B {
public int t;
public B(int t) {
this.t = t;
}
}
I thought that any changes I did after A a = new A(s, array, b); would affect a. Don't all the fields of a and the variables s, array, b refer to the same object?
String s = "Lorem";
int array[] = new int[] {
10, 20, 30
};
B b = new B(12);
A a = new A(s, array, b);
s = "Dolor";
array = new int[] {
23
};
b = new B(777); // Initialized with a new value, a.b keeps the old one. Why?
System.out.println(a);
The output.
String Lorem
Array [10, 20, 30]
B 12
And about this.
B b2 = new B(89);
B b3 = b2;
System.out.println(b3);
b2 = null;
System.out.println(b3); // b2 initialized with null, b3 keeps the old one. Why?
The output.
89
89
However, if I have two lists, this shows that they both refer to same object.
ArrayList<String> first = new ArrayList<String>();
first.add("Ipsum");
ArrayList<String> second = new ArrayList<String>();
second = first;
first.add("The Earth");
System.out.println(second);
The output.
[Ipsum, The Earth]
The difference is assignment versus modification.
Assignment (=) makes the variable point to something else, so this won't change the underlying data. So any other variables pointing to the same data don't change.
Modification (pretty much anything except =) doesn't change what the variable points to, it just modifies the underlying object. So any other variables pointing to the same data do change.
For you example:
b = new B(777); is assignment, so only b is changed to point to something else. a.b won't change.
b2 = null; is assignment, so only b2 is changed to point to something else. b3 won't change.
If you were to say b2.t = 5, this would be modification (we're not assigning a new value to b2, we're modifying it by changing one of its members), so b3 will change as well.
I hope that explains it.
No. The thing is, you are not changing a, you are assigning a new value to s. S is a String, which are immutable, which means you can never make a change to the value of s. You can, however, change the reference in S, which is what you are doing.
To make yourself more clear try these lines of code..
String s = "Lorem";
int array[] = new int[] {10, 20, 30};
B b = new B(12);
//A a = new A(s, array, b);
s = "Dolor";
array = new int[] {23};
b = new B(777);
A a = new A(s, array, b);
System.out.println(a);
ArrayList<String> first = new ArrayList<String>();
first.add("Ipsum");
ArrayList<String> second = new ArrayList<String>();
second = first;
second.add("The Earth");
first.remove("The Earth");
System.out.println("second :"+second);
What are the current values the String s, array and the object b are holding while creating the instance of class A ( at the time of calling class A constructor ) will be printed. After creating class A instance, the String s, array and object b will be referred as a.s, a.array and so. If you assign a new value to s, array and b, it wont affect the class A instance.
And for the array list question, the two array lists will refer the same reference only. If you want different reference then do like this... (But always = assign operator will make same reference only )
ArrayList<String> first = new ArrayList<String>();
first.add("Ipsum");
ArrayList<String> second = new ArrayList<String>(first);
second.add("The Earth");
System.out.println("first :"+first);
System.out.println("second :"+second);
Thanks Dukeling for explaing how assignments works with objects and primitives, I am adding here to explain how the list works when operations performed on them.
When we consider the two array lists created in the above code in the question, both the variables first and second are pointing to the same array object that resides in the memory.
So when an add operation is performed the underlying object itself gets updated. So the print operation prints the second array list which pointed to the same array-list object created during the creation of first array-list.