Clone method for Java arrays - java

What exactly does the clone() method in Java return when used on an array?
Does it return a new array with data copied from the original?
Ex:
int[] a = {1,2,3};
int[] b = a.clone();

When the clone method is invoked upon an array, it returns a reference to a new array which contains (or references) the same elements as the source array.
So in your example, int[] a is a separate object instance created on the heap and int[] b is a separate object instance created on the heap. (Remember all arrays are objects).
int[] a = {1,2,3};
int[] b = a.clone();
System.out.println(a == b ? "Same Instance":"Different Instance");
//Outputs different instance
If were to modify int[] b the changes would not be reflected on int[] a since the two are separate object instances.
b[0] = 5;
System.out.println(a[0]);
System.out.println(b[0]);
//Outputs: 1
// 5
This becomes slightly more complicated when the source array contains objects. The clone method will return a reference to a new array, which references the same objects as the source array.
So if we have the class Dog...
class Dog{
private String name;
public Dog(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and I create and populate an array of type Dog...
Dog[] myDogs = new Dog[4];
myDogs[0] = new Dog("Wolf");
myDogs[1] = new Dog("Pepper");
myDogs[2] = new Dog("Bullet");
myDogs[3] = new Dog("Sadie");
then clone dog...
Dog[] myDogsClone = myDogs.clone();
the arrays refer to the same elements...
System.out.println(myDogs[0] == myDogsClone[0] ? "Same":"Different");
System.out.println(myDogs[1] == myDogsClone[1] ? "Same":"Different");
System.out.println(myDogs[2] == myDogsClone[2] ? "Same":"Different");
System.out.println(myDogs[3] == myDogsClone[3] ? "Same":"Different");
//Outputs Same (4 Times)
This means if we modify an object accessed through the cloned array, the changes will be reflected when we access the same object in the source array, since they point to the same reference.
myDogsClone[0].setName("Ruff");
System.out.println(myDogs[0].getName());
//Outputs Ruff
However, changes to the array itself will only affect that array.
myDogsClone[1] = new Dog("Spot");
System.out.println(myDogsClone[1].getName());
System.out.println(myDogs[1].getName());
//Outputs Spot
// Pepper
If you generally understand how object references work, it is easy to understand how arrays of objects are impacted by cloning and modifications. To gain further insight into references and primitives I would suggest reading this excellent article.
Gist of Source Code

clone() method creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression:
x.clone() != x
Will be true, and that the expression:
x.clone().getClass() == x.getClass()
Will be true, but these are not absolute requirements.
While it is typically the case that:
x.clone().equals(x)
will be true, this is not an absolute requirement.
By convention, the returned object should be obtained by calling super.clone. If a class and all of its superclasses (except Object) obey this convention, it will be the case that x.clone().getClass() == x.getClass().

Related

Polymorphism. Problems with copy arrays

Empleado[] empleados = new Empleado[3];
empleados[0] = new Empleado("Alfredo", 20000, 2020, 6, 01);
empleados[1] = new Empleado("Alejandro", 21000, 2020, 7, 04);
empleados[2] = new Jefatura("Laura", 25000, 2010, 3, 6);
Jefatura jefeRRHH = (Jefatura) empleados[3]; // CASTEO
jefeRRHH.setIncentivo(1000);
Why is it that when i set the incentive for jefeRRHH, empleados[2] is changed? I thought if jefeRRHH was modified this didn't affect the array empleados.
I mean, when I walk the vector with a foreach loop, empleados[2] give me back with the incentive applied.
package poo;
public class test {
public static void main(String[] args) {
String Nombre = "José";
int j = 1;
String[] nombres = new String[1];
nombres[0] = Nombre;
int a = j;
Nombre= "Maria";
System.out.println(Nombre);
System.out.println(nombres[0]);
j=2;
System.out.println(j);
System.out.println(a);
}
}
Why isn't the same thing here?
When I declare the new variables I'm not assigning addresses, I'm assigning copies, right?
The following will hold true for all Objects in Java.
Assuming a simple class:
public class Foo {
}
When you then instantiate an object of class Foo, you will actually allocate memory on heap, construct a Foo-Object and retrieve the adress to this location, which will then be stored in the object variable:
Foo f = new Foo(); // f points to a Foo-Object
So, instead of copying the actual object, the reference will be copied...
Foo farr[] = new Foo[1]; // create array with a capacity of 1
Foo f = new Foo(); // f now holds the adress to an actual Foo-Object
farr[0] = f; // farr[0] now holds the adress to the SAME Foo-Object
Here is a nice article about references and objects,
and here is a nice answer as follow-up-reading
Furthermore there are primitive datatypes and String-literals.
Primitive datatypes are always simply copied, whatever happens. So there will never be the case, where you change one primitive variable and another one changes.
Strings on the other hand are a bit trickier. They are objects wrapped around a char[], and therefore are (as already stated by others here) immutable and share a so called String constant pool. Modifying a String will therefore result in a new String with the result, and the original String remains unmodified.
You probably have a typo in the code, you should reference the element with index 2 here:
Jefatura jefeRRHH = (Jefatura) empleados[3]; // CASTEO
So, you create a new object with
new Jefatura("Laura", 25000, 2010, 3, 6);
and store a reference to it in the element of the empleados array with index 2. Then you say that jefeRRHH will be another reference to the same object. Now you have two references pointing at the same object. Think about them like different names (or nicknames if you like) of the same person. When you access/modify the object using any of the references you change the same object, so the changes are visible through any other names/references.

What's the difference between == and .equals in Java?

I have seen many articles saying that is a reference comparison, i.e. both objects point to the same memory location .equals() evaluates to the comparison of values in the objects.
But I don't understand what this means, because when I tried understanding the following code, the strings printed were "Different" and "Not same". How is that possible? What does .equals mean? Am I understanding this all wrong? I thought the answer would be "Different" and "Same"?
import java.util.Arrays;
public class HelloWorld {
public static void main(String[] args) {
int arr1[] = {1, 2, 3};
int arr2[] = {1, 2, 3};
if (arr1 == arr2){
System.out.println("Same");
} else {
System.out.println("Different");
}
if (arr1.equals(arr2)){
System.out.println("Same");}
} else {
System.out.println("Not same");
}
}
}
Yes, == with objects is a reference comparison* (checks if the operands are references to the same object), while equals is whatever the class involved defines it to mean (within the requirements documented for equals). Some classes define equals as being the same as ==, including Java's arrays. (Because they don't override the default implementation from Object.equals, which uses ==.)
If you want to compare Java arrays based on the equality of their contents, you use Arrays.equals instead.
Your experiment would have worked if you used a class that defined equals in a useful way, you were just unlucky picking arrays. It's a bit tricky to find a class in the JVM to use for this experiment, because so many either don't implement equals (like arrays) or could be confusing because there are several immutable classes which may reuse instances (although not if you explicitly use new; but I don't want to go down a path of having you use new with something you probably shouldn't, like String; more on that here). I'm going to give up on picking a good example and use the slightly old class SimpleDateFormat:
DateFormat a = new SimpleDateFormat("yyyy-MM-dd");
DateFormat b = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(a == b ? "== Same" : "== Different");
System.out.println(a.equals(b) ? "equals Same" : "equals Different");
That outputs
== Different
equals Same
because SimpleDateFormat defines equals to check that the other object is also a SimpleDateFormat with the same formatting.
Live example
Re your comment on the question:
I have someone the answer points but I only get the == part, if .equals is checking the content, how come the code didnt print "same" for the second if
Because equals doesn't, necessarily, check content. It only does if a class overrides the default Object.equals (which just uses ==) and implements a content check. Arrays don't. (One could argue that they should have, but they don't.) Other classes, like SimpleDateFormat and String and Integer and HashMap do.
In essence: == is always a reference comparison. equals may or may not be a contents comparison, depending on what class you're using it on.
So for instance, say we have this class:
class Example1
{
private int content;
Example1(int content) {
this.content = content;
}
public static void main (String[] args) throws java.lang.Exception
{
Example1 a = new Example1(42);
Example1 b = new Example1(42);
System.out.println(a == b ? "== Same" : "== Different");
System.out.println(a.equals(b) ? "equals Same" : "equals Different");
}
}
Since that class doesn't override equals, you'll get the same answer ("Different") for both == and equals. Live Example.
But if we override equals to define what it would mean for two instances to be equal (in this case: because they have the same content):
class Example2
{
private int content;
Example2(int content) {
this.content = content;
}
#Override
public boolean equals(Object obj) {
if (obj == null || !obj.getClass().equals(this.getClass())) {
return false;
}
Example2 other = (Example2)obj;
return this.content == other.content;
}
#Override
public int hashCode() {
return this.content;
}
public static void main (String[] args) throws java.lang.Exception
{
Example2 a = new Example2(42);
Example2 b = new Example2(42);
System.out.println(a == b ? "== Same" : "== Different");
System.out.println(a.equals(b) ? "equals Same" : "equals Different");
}
}
Now equals says two instances with the same content are the same, because the class defines what that means. Live Example. (Also note that when overriding equals, you must override hashCode, which is why I've done so above.)
* More generally, == tests if the values of its operands are the same. The value in the case of reference types is an object reference, and two object reference values are only the same when they refer to the same object are are only different when they refer to different objects (or one of them is null; not referring to an object at all).
To create object you need some portion of memory to store it.
Operator == checks if two variables point to the same memory block. That is they points to the same object instance (they are one person under different aliases).
equals() is a method and checks equality by some algorithm. Meaning two object contain the same data (they are different persons but with the same face, twins for example). Default implementation for java.lang.Object#equals is
public boolean equals(Object obj) {
return (this == obj);
}
Using you IDE you can ensure that equals for an array is actually java.lang.Object#equals. To check two arrays for equality you should use Arrays.equals. It has also a lot of other useful methods for manipulating with arrays. It is a good idea to check this class first when you need to do something with an array. It saves much time and code lines.
EDITED
Arrays (int[], float[], String[], AnyClass[]) does not implement custom equals method. So for array and for any your custom class equals() and == do same operation unless you override equals() and provide custom comparison. Like
public class Person {
public String name;
public String surname;
public Person(String name, String surname) {
this.name = name;
this.surname = surname;
}
public boolean equals(Object thatObj) {
if (thatObj instanceof Person) {
Person that = (Person) thatObj;
return this.name.equals(that.name) &&
this.surname.equals(that.surname);
}
return false;
}
}
I always use below example to understand the difference between == and .equals,
String s1 = new String( "Test" );
String s2 = new String( "Test" );
System.out.println( s1 == s2 ); // will print 'false'
System.out.println( s1.equals( s2 )); // will print 'true'
since new keyword always create fresh new objects it will have 2 different references. Therefor, == comparison will return false. This happens because it is comparing the reference value(or someone can say memory location value) only which different. However, If you initialize the same thing like below(auto boxing),
String s1 = "Test";
String s2 = "Test";
System.out.println( s1 == s2 ); // will print 'true'
System.out.println( s1.equals( s2 )); // will print 'true'
Now s1 and s2 both will use the same object and same reference.
the == compare the reference. in your example when you create the variable arr1[] it created in memory and had it own address in the memory so when you create another variable arr2[] it created in memory but with another address so when you compare arr1 address is not equal to arr2 address. but when you use .equal it does not compare the memeory location but instead it compare the value inside.
if you want arr1 to arr2 == each other it must be like this :
arr1[] = [1,2,3]
arr2[] = arr1;
then arr1 == arr2 //true

Unexpected result when use swap function to swap two references in Java

I have two references, reference a point to object a, reference b point to object b, then I called a swap function to try to let a point to object b, b point to object a, it is swapped in the swap function, but result in main function didn't change. So what I should do?
The swap function:
private void swap(Stack<TreeNode> a, Stack<TreeNode> b) {
Stack<TreeNode> temp = new Stack<TreeNode>();
temp = a;
a = b;
b = temp;
}
The result of the swap is local to the method, it won't have any effect once the method returns to its calling point - you're simply swapping local variables. When the method got invoked, a copy of a reference to the objects got passed, not the actual objects themselves.
Java has pass-by-value semantics, in the case of objects being passed as parameters to a method that means that a copy of the reference is passed. Take a look at this post for an example.
Also notice that the object references existing before calling the method, and the references existing inside the method as parameters are actually pointing to the same object, so any modifications to the object's contents you do inside a method will remain in place once the method returns.
You're changing local parameters, not the acutal contents of those references. One solution is to modify the instances you're sending. E.g.
private boolean swap(Stack<TreeNode> a, Stack<TreeNode> b)
{
if(a == null || b == null) return false;
Stack<TreeNode> temp = new Stack<>();
while(!a.empty()) temp.add(a.pop());
while(!b.empty()) a.add(0, b.pop());
while(!temp.empty()) b.add(temp.pop());
return true;
}

clone() and system.arracopy() of an array creates two arrays with different references in Java?

Firstly I have to say this is not a duplicate of deep copying vs shallow copying (clone) in Java. but it is related to that. I have read other posts on deep vs shallow copying in SO and while working on this, I found some problem with my understanding.
Question is : clone() and system.arraycopy() gives different arrays in the below example. but they aren't supposed to?
I used array as a field in another example object below. There again I see they are different references for the arrays fields. The code is commented for easy following.
import java.util.Arrays;
import java.util.*;
class Example {
public int foo;
public int[] bar;
public Example (int foo, int[] bar) {
this.foo = foo;
this.bar = bar;
}
public void setfoo(int foo){
this.foo=foo;
}
public int[] getbar(){
return bar;
}
}
public class ClonevsDeepCopy {
public static void main(String[] args){
//Example 1
StringBuffer[] arr = {new StringBuffer("abc"),new StringBuffer("def"),
new StringBuffer("ghi")};
StringBuffer[] arr2 = arr.clone();
StringBuffer[] arr3 = new StringBuffer[3];
System.arraycopy(arr, 0, arr3, 0, 2);
//check for identity
System.out.println(arr==arr2);
System.out.println(arr==arr3);
//End of example 1
//Example 2
/*this is equivalent of shallow copying which is clone()
* The normal interpretation is that a "shallow" copy of eg1
* would be a new Example object whose foo equals 1
* and whose bar field refers to the same array as in the original; e.g.
*/
Example eg1 = new Example(1, new int[]{1, 2});
Example eg2 = new Example(eg1.foo,eg1.bar);
System.out.println(eg1.bar==eg2.bar);
eg1.setfoo(4);
eg1.bar[0]=99;
/*This is equivalent of deep coying
The normal interpretation of a "deep" copy of eg1 would
be a new Example object whose foo equals
1 and whose bar field refers to a copy of the original array; e.g.
*/
Example eg3 = new Example(eg1.foo,Arrays.copyOfRange(eg1.bar, 0, 2));
System.out.println(eg3.bar==eg1.bar);
//cloning on array
Example eg4 = new Example(eg1.foo,eg1.bar.clone());
System.out.println(eg4.bar==eg1.bar);
//End of example 2
}
}
There's nothing strange here.
If arr1 is the result or arr.clone() then arr1!=arr but arr1[0]==arr[0] if it is defined. If arr1=arr is the assignment then arr1==arr.
Details:
We have 5 results:
false at System.out.println(arr==arr2);:
Nothing strange here, we're comparing the array references themselves, not the contents.
false at System.out.println(arr==arr3);
Nothing strange, different arrays.
true at System.out.println(eg1.bar==eg2.bar);:
Nothing strange, same references.
Last two false:
Again, we're performing some shallow copies. The elements are still equal references, but the arrays are different references.
I don't know what is confusing you. System.arraycopy() copies elements from one array to another. It doesn't play with reference.
Array#clone() javadoc states
The general intent is that, for any object x, the expression:
x.clone() != x
Therefore you will get different references.
More detail
StringBuffer[] arr = {new StringBuffer("abc"),new StringBuffer("def"),
new StringBuffer("ghi")};
StringBuffer[] arr2 = arr.clone();
StringBuffer[] arr3 = new StringBuffer[3];
You have 3 different references. Then, see code comments
System.arraycopy(arr, 0, arr3, 0, 2); // copy values from arr into arr, the references haven't changed
//check for identity
System.out.println(arr==arr2); // different references
System.out.println(arr==arr3); // different references
Arrays.copyOf() returns a new array (new reference) with values from the source array.
Example eg3 = new Example(eg1.foo,Arrays.copyOfRange(eg1.bar, 0, 2));
Therefore
System.out.println(eg3.bar==eg1.bar);
is false.
And more
Example eg4 = new Example(eg1.foo,eg1.bar.clone());
System.out.println(eg4.bar==eg1.bar);
clone() returns a new reference, so you are again comparing different references and get false.
If you're looking to compare the contents of the arrays, use
Arrays.equals(arr, arr2); // for example
Note that here it doesn't matter because of primitive types, but if your array held reference types, you might care about shallow or deep copies.
Much confusion will be avoided if you regard type object and all its derivatives as holding "object identifiers". A variable of type StringBuffer doesn't hold an instance of StringBuffer--it holds an object identifier which, if non-blank (i.e. not null), will identify an instance of StringBuffer. Likewise, a variable of type StringBuffer[] doesn't hold an array--it holds an object identifier which, if non-blank, will identify an instance of StringBuffer[] which, in turn, won't hold instances of StringBuffer, but will instead identify them.
When code says someVariable.someMember=5;, the code isn't writing to someVariable. Instead, it examines someVariable, notices which object it identifies, and then modifies the appropriate field of that object. It may look as though the right-hand part of the statement has something to do with someVariable, but it doesn't. Once the system determines what object is identified by someVariable, that variable will be out of the picture.

Java Heap and Pass By Value

I am a little confused as to how my Java program is allocating memory. Below is a typical situation in my program. I have an object created on the Heap inside of a class which I pass to other functions inside of other classes.
public class A {
private List<Integer> list = new ArrayList<Integer>();
public A() {
for(int i = 0; i < 100; i++)
list.add(i);
}
public void foo() {
B b = new B();
b.bar(this.list);
}
}
public class B {
A a = new A();
public int bar(List<Integer> list) {
list.add(-1);
return list.size();
}
public int getSize() {
List<Integer> list = a.list;
return a.size();
}
}
My question(s) are about how the memory is used. When A's list gets passed to B.bar(), does the memory get copied? Java is pass-by-value so I assumed the B.bar() function now contains a copy of the list which is also allocated on the heap? Or does it duplicate the list and put it on the stack? Or is the list duplicated at all? Similarly what applies to these memory questions inside of B.getSize()?
It's probably clearer to say that in Java, object references are passed by value.
So B gets a copy of the reference (which is a value) to the List, but not a copy of the List itself.
You can easily prove this to yourself by getting B to modify the List (by adding or removing something), and observing that A's List also changes (i.e. it is the same List).
However, if you change B's reference to the List (by creating and assigning a new List to it), A's reference is unchanged.
Java is pass-by-value, but the value of an expression or variable is always either a primitive or a reference. A reference, in turn, is either null or a pointer to some object.
In your case: private List<Integer> list = new ArrayList<Integer>(); declares list as having a reference type, and makes its value a pointer to a newly allocated ArrayList object.
When you use list as an actual argument, for example on the b.bar(this.list); call, the formal argument list in b.bar is initialized with a copy of that pointer. That is, bar's formal argument points to the same ArrayList object as A created. The ArrayList object is not copied.
Java is pass-by-value, dammit!
However, you only ever have access to references to Objects. In that sense, you are passing Object references by value.

Categories

Resources