Java copying understanding - java

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.

Related

What is Object[] exactly?

I am having difficulty understanding what an Object[] is. Is it an Array that keeps Objects ? For example what happens when we do this :
int a = 5;
String b = "Hi";
Object[] c = { a, b };
Did I just create an object with properties a and b added to it ? Or did I get an Object Array in which a and b was counted as objects and elements of this c the object array ?
Thanks.
Actually you created an array of objects derived from Object (which is true for all object in Java), now containing an Integer (created by autoboxing) on position 0, and a String on position 1.
Java is not dynamically typed so you cannot add properties on the fly like in javascript (without reflection). Btw. in java you dont call them properties, but instance-members/fields or methods if its a function, which are defined in classes (but you usually work with instances which is constructed from a class). So Object is a class and Object obj = new Object(); obj is an instance
The notation ClassName[] always notates an array of type ClassName, so
Object[]
notates an array of objects. And
String[]
an array that can only contain Strings.
You can initialize an array with
Object[] objArr = new Object[3];
which creates a new empty array which can hold 3 elements. Or you can directly set the elements by
Object[] objArr = {"elem1","elem2","elem3"};
which creates an array with 3 elements (elem1-3). So therefore:
System.out.println(objArr[0]); //"elem1"
System.out.println(objArr[1]); //"elem2"
System.out.println(objArr[2]); //"elem3"
System.out.println(objArr[3]); // ArrayIndexOutOfBoundsException
Because you used Objectas a type you can set practically anything to the array since any class automatically inherits from Object
Object[] objArr = {"elem1",2.34,new Date()};
System.out.println(objArr[0]); //"elem1"
System.out.println(objArr[1]); //2.34
System.out.println(objArr[2]); //11.05.2014
2.34 is a double, so a primitive, but since 1.4 java autoboxes every primitive into its Object pendant (so Double), thats why it works. Note that usually in a statically typed language you dont want to do that this way since you lose alle the advantages of statical type checks, so better define your types and use them.
Did I just create an object with properties a and b added to it ?
No. Those are elements. Properties != Elements.
did I get an Object Array in which a and b was counted as objects and elements of this c the object array ?
Little wrong. Counted as elements, which are objects.
Object[] c = { a, b }; // a is Integer and b is String
When you write the above line, that means you created an array Objects with elements a and b in it. You can refer the array with c
Is it an Array that keeps Objects ?
To be precise, it's an Object that contains references to other Objects.
All objects in Java are created and live on the heap until the garbage collector reclaims them. References point to those memory locations and give your program access.
The example you gave uses two immutable objects. The real fun would happen if you chose a mutable object and added it to your array.
On executing the program it will print,
5
Hi
on iterating the array. that shows the Object array consist of a of Integer and b of String.
It's an array of objects. You've auto-boxed a from a primitive int into an Integer and added that, and String b to the Object array. Remember all Objects extend Object. Try casting the Objects to their subclass types and maybe this will help you understand what's going on. E.G.
int a2 = (Integer) c[0];
String b2 = (String) c[1];
Object[] is an array of object references. From your code, imagine you did this:
int a = 5;
String b = "Hi";
Object o1 = a; // Autoboxes to java.lang.Integer
Object o2 = b;
Pretty similar to:
int a = 5;
String b = "Hi";
Object[] c = new Object[2];
c[0] = a;
c[1] = b;
... right? Which is exactly what your code above does, in a more shorthand way. So, you create an array where each element holds a reference to an Object.
Objects are superclasses of every non-primitive in Java. In your code:
int a = 5; // <- int is a primitive
String b = "Hi"; // <- String is a subclass of Object
Object[] c = { a, b };
c wants to have an array of Objects, and since a is an int, autoboxing occurs (this means that the compiler makes the int an Integer-object). You can compare it to the following code (this is basically what the compiler does behind the scenes).
int a = 5; // <- int is a primitive
String b = "Hi"; // <- String is a subclass of Object
Object[] c = { new Integer(a), b }; // <- int is autoboxed to it's container-class Integer
As I mentioned, Objects are the superclass of every non-primive in Java. So let's compare your code to the following:
I have three classes:
class C{ } // Just compare this with Object
class B extends C{ } // Compare this with String
class A extends C{ } // Compare this with Integer
// translating your code to:
A a = new A();
B b = new B();
C[] c = { a, b };
The left side is the reference type and the right side is the object type.
// List is the reference type, ArrayList is the object type
List<String> list = new ArrayList<String>(); // (or List<String> list = new ArrayList<>(); in Java 7+)
// With the C, B and A classes above:
// C is the reference type, A is the object type
C myClass = new A();

Is array size irrelevant in java?

As per the below statement,
An array of subclass may be assigned to an array of its superclass. An array of implementing class may be assigned to an array of its interface type. Size is irrelevant.
I wrote below sample code to check the behavior of size in array
interface I{}
class C implements I{}
/* dummy.java*/
public class dummy{
public static void main(String[] args){
C[] c = new C[6];
I[] i = new I[2];
c[0] = new C();
c[1] = new C();
c[2] = new C();
c[3] = new C();
c[4] = new C();
c[5] = new C();
i = c;
System.out.println(i[5].getClass());
}
}
When i say, new C[6];, an object [null,null,null,null,null,null] gets created of type class [LC and c points to this object. When i say, new I[2];, an object [null,null] gets created of type class [LI and i points to this object.
My question:
How interface array is working here, when i say i[5], despite an object [null, null] being created after defining new I[2]? What exactly is happening when i say i = c;? Is size of array of interface new I[2]; getting modified during assignment i = c;?
What that quote is trying to say is that the size of an array is part of the object, ie. it is not part of the reference or the variable type.
In
i = c;
you are assigning a copy of the value of the reference held in c to i. That is, i will reference the same instance as c.
Is size of array of interface new I[2]; getting modified during assignment i=c;?
No, that's the whole point. i and c are just variables. Variable assignment has no side effects.
When you set
i=c
You are setting i to point to the object created by c. Therefore, i will now point to C[6]; < this array
So...
i[1] = new I();
c[1] will return a I object

If arrays are object in java why the assignment between arrays is deep copy

If arrays are object as stated in Is an array an object in java then why the output of the code snipped below is [1,1,1]?
I thought after the execution of statement "a=b;" a and b are still pointing to the same content! Isn't it supposed to be shadow copy between objects?
import java.util.Arrays;
public class Local {
int [] a = null;
public Local(){
int [] b = {1,1,1};
int [] c = {5,5};
a=b;
b=c;// 'a' should change too as a and b are both objects! right?
}
public static void main(String[] args) {
Local local = new Local();
System.out.println(Arrays.toString(local.a));
}
}
Let me try to explain it line per line:
int [] b = {1,1,1};
On this line, three things happened.
Created a variable named b.
Created an array of int {1,1,1}
Assigned b to the array of intcreated on step 2.
int [] c = {5,5};
Same thing happened here
Created a variable named c.
Created an array of int {5,5}
Assigned c to the array of int created on step 2.
a=b;
Now we also assigned a to whatever the value of b is, which in this case is the array of int {1,1,1}
Now we have something like
b=c; // 'a' should change too as a and b are both objects! right?
What happened here is that we assigned b to whatever c's value is (int array {5,5}), now b is not pointing to {1,1,1} anymore and since Java is pass by value, a's value remained. It's not like a is pointing to the reference of b that whatever b is pointing to, a will point to it too.
Hope this helps.
// 'a' should change too as a and b are both objects! right?
No both a and b are just reference variables pointing to the same array object {1,1,1}.
With the below line you are making b to refer to altogether different array object where as a would still be pointing to the same array object {1,1,1} as the reference of only b but not a is changed by executing the below line
b = new int[] {2, 2};
Also by making a = b you are making them point to one single array object {1,1,1} and there is no deep/shallow copy happening here.
the variable a would not automatically update itself. mainly because
b = c //is like b = new int[]{5,5};
it is the same concept in your question earlier with
b = new int[]{2,2,2};
a is pointing to b's int array which is [1,1,1]
and you are telling b to point to c which is [5,5]
a => b's array
b => c's array
so a will retain its object and b will have a new one.
At first, b is pointed to the array object {1,1,1}
and you assign b to a, so a is pointed to {1,1,1}
so the out is {1,1,1}

Call by reference or Call by value

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;
}
}

Why is this Java array considered two dimensional?

Consider this code:
class arraytest {
public static void main(String args[]) {
int[] a = null , b[] = null;
b = a;
System.out.println( b );
}
}
The line
b = a;
is flagged by the compiler saying:
Incompatible types, found int[], required int [][]
Why is b considered two dimensional? I realize the "shortcut" declaration
int[] a = null , b[] = null;
is to blame, but why does it make the array two dimensional when only one set of brackets have been written? I find this syntax unclear and obfuscating.
Take this example:
int a, b;
Then both a and b are ints, right? So now take this:
int[] a, b;
The both a and b are int arrays. So by adding another set of brackets:
int[] a, b[];
you have added another set of brackets to b.
Either of these would be fine:
int[] a = null , b = null;
int a[] = null , b[] = null;
or as you say, simply putting them on separate lines would work too (and be much easier to read).
int[] a = null , b[] =null;
.... it's equal to :
int[] a = null;
int[][]b = null;
You have to do :
int[] a = null , b =null;
In addition to the other answers, Java does not have multi-dimensional arrays. Java has arrays of any type. This "any type" may itself be an array. Multi-dimensional arrays are distinctly different, although subtly.
If you take out the a declaration, this is what you have:
int[] b[] = null;
which is, unfortunately, a legal alternative to
int[][] b = null;
I was lead to believe that the syntax of allowing the [] after the b was there solely for the C-language crowd who would feel more at home with it. Unfortunately, it has the side effect of allowing confusing declarations like
int[] b[];
which ends up the same as
int[][] b;

Categories