Polymorphism. Problems with copy arrays - java

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.

Related

Does ArrayList Actually Stores references only

I have read it everywhere that Java stores Object references in array. Even i demonstrated it myself.
But then i changed the state of the object, means i changed the values of attributes and saved in array, and i can retrieve multiple state of same object. If Array saves only references then how do references holds the states.
For example:
class Test{
String id;
}
Test[] testArr = new Test[2];
test = new Test();
test.id = "ABC"
testArr.add(test)
test.id = "XYZ"
testArr.add(test)
now in case above if we would storing only references then second assignment would have overwritten id value of test object and both entry in array would have same value of id, but this is not the case and we can retrieve the id values ABC and XYZ. I am confused!
Take a look at this code:
class Test {
String id = "A";
}
public class Main {
public static void main(String[] args) {
ArrayList<Test> list = new ArrayList<Test>();
// Adding some Test Object to the list.
Test foo = new Test();
list.add(foo);
System.out.println("Value of foo id: " + foo.id);
// Retrieving the Object from the list & changing the value
Test bar = list.get(0);
bar.id = "B";
System.out.println("Value of foo id: " + foo.id);
}
}
output:
Value of foo id: A
Value of foo id: B
As you can see the arraylist only holds references. If you retrieve the Object from the list and change something in it, the original Object will be changed too
To answer your question. Yes. All variables are simply references to the location of an object, not just an ArrayList. Writing MyObject obj = new MyObject(); creates a new object however the variable obj is just a reference to the location of that object in the Heap (aka memory).
An ArrayList (without looking at its actual implementation) simply stores each reference to the location of an object as an index of the ArrayList rather than a unique variable.
In a bit more detail: You need to understand what each part of creating an object does. Try to imagine it in this way:
Each object is located in a memory address that takes up the number of bytes all its fields use. Lets imagine we have an object called MyObject that takes up 100 bytes. When we create an Object using the new keyword (ie. new MyObject()) it is stored in a memory location in the heap (which is an area of memory set aside for your program to use as dynamic memory allocation). Let us say that when this object is created it takes up memory space 1000 (up to 1100 because it uses 100 bytes of memory). So:
|MyObject| <-- this is a visualization of memory space
1000
The when we write MyObject obj it sets aside memory in the stack (which is used for static memory allocation) and this will hold the location of the object. So it may hold the reference to the location of the object in its own location which we will pretend is labeled 4
|______| <- empty memory location because it hasn't been assigned yet.
4
When we put the 2 instruction together and write MyObject obj = new MyObject() it puts the address of the object into the memory location of the variable so we end up with:
|MyObject| <-- location of actual object
1000
|1000| <-- location of variable which a reference to the location of the object
4

What causes java to treat this two object types of ArrayLists and Integers differently?

Both ArrayList and Integer are object data type, but why the code below treats the two differently?
ar,br,a and b are all objects.
Changing ar changes br, but changing a did not change b why? Isn't it both ArrayLists and Integers are objects? assignign an object to another object by using = statement simply does the shallow copy FOR BOTH? or no?
import java.util.ArrayList;
import java.util.Arrays;
public class MyClass {
public static void main(String[] args) {
ArrayList <Integer> ar = new ArrayList<>(Arrays.asList(1,2,3));
ArrayList<Integer> br = ar;
System.out.println(Arrays.toString(br.toArray()));// [1,2,3]
ar.remove(0);// lets change ar
// now lets see if br changed too
System.out.println(Arrays.toString(br.toArray()));// [2,3] (yes did)
Integer a= new Integer (5);
Integer b = a;
a = a+1;// lets change a and see if b changed too
System.out.println(b);// b is still 5
//So changing ar changed br too, but changing a did not change b why? Ist it both br and b are objects?
}
}
This is because Integer objects are actually boxed primitives. When you call Integer a= new Integer (5);, you create a new Integer. When you execute Integer b = a;, then b refers to the same instance of Integer as a.
When you call a = a+1;, the following happens:
a is unboxed into a primitive int with value 5.
The result of adding one to that int is evaluated.
The result, 6, is boxed into a new Integer that has a value of 6. The original integer of value 5 is not modified.
In the case of the list, you are assigning both ar and br to refer to the same instance of java.util.ArrayList. Modifications to that arraylist are seen when you access it through both ar and br.
The critical point is that a = a+1 constructs a new java.lang.Integer() through unboxing, evaluation, and boxing, while ar.remove(0); affects that list without creating a new copy of it.
More JLS reading:
If p is a value of type int, then boxing conversion converts p into a reference r of class and type Integer, such that r.intValue() == p
You need to understand the difference between variables, reference values (and dereferencing for field access and method invocation), and objects.
A variable is just a holder for a value.
A reference value is a value which is interpreted as the location of an object.
An object is ... an object. It has accessible fields and invocable methods.
Here
ArrayList <Integer> ar = new ArrayList<>(Arrays.asList(1,2,3));
ArrayList<Integer> br = ar;
You create two variables which store a single reference value which points to the single instance created with new ArrayList<>(..). So both variables are referencing the same object.
When you invoke a method by using a method invocation expression
ar.remove(..);
the JVM uses the reference value to find the object and invokes its method. This is the same object referenced by br. So when you then do
br.toArray()
you're still accessing the same object.
Here
Integer a = new Integer (5);
Integer b = a;
you create two variables that are referencing the same object.
Then you do
a = a+1;// lets change a and see if b changed too
which assigns (=) a new reference value to the variable a. So now a references a different object than b.
So:
ArrayList <Integer> ar = new ArrayList<>(Arrays.asList(1,2,3));
ArrayList<Integer> br = ar;
System.out.println(Arrays.toString(br.toArray()));// [1,2,3]
ar and br are the same instance
ar.remove(0);// lets change ar
// now lets see if br changed too
System.out.println(Arrays.toString(br.toArray()));// [2,3] (yes did)
The content of ar is changed. Since ar == br, the change can be seen in br.
Integer a = new Integer (5);
Integer b = a;
a is a new object, and again b is assigned to be the same instance
a = a+1; // lets change a and see if b changed too
System.out.println(b); // b is still 5
The reference of a is changed. a now points to a newly created object. b still points to the first created object.
this was just asked, earlier today, the Integer b is immutable and wont change, but the arraylist is just a reference...

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.

Clone method for Java arrays

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().

Is it safe to re-use variables inside a method?

I have an array of type string which I want to re-use inside a method.
I need to pass it to a function which returns a subset of the elements of array passed. To capture the returned array from function, should I declare a new string array or can I safely re-use same array that was holding the unfiltered array to hold filtered array ??
Also clarify that, when I pass a variable like array to a function does it creates a new space for the array in the heap each time I pass it as parameter to further functions or just it uses the same space in the heap & just passes the reference? I guess in case of array it passes just the reference but in case of simple variables it allocates new space on stack, right?
EDIT: Thanks you all for the great answers and explanations!!
Please also clarify whether that if I am reusing the array, would I be required to set the null at the position when I end the subset of array ? (Actually the subset of my array is not directly calculated from the array but some other calulations, so I would be required to manually set the null otherwise the older elements of the list would be visible, right??)
when I pass a variable like array to a function does it creates a new space for the array in the heap each time I pass it as parameter to further functions or just it uses the same space in the heap & just passes the reference
Java is entirely pass by value, but with arrays and object types, the value being passed is a reference (pointer) to the actual object, which is not duplicated. So when you pass an array into a function, only the reference to the array is copied; the array itself isn't. That's why if a function modifies the contents of an array, the code calling the function sees the modifications.
Example:
// A method that changes the first entry in an array
void changeArray(String[] theArray) {
theArray[0] = "Updated";
}
// A method that uses the above
void someMethod() {
String[] foo = new String[3];
foo[0] = "Original 0";
foo[1] = "Original 1";
foo[2] = "Original 2";
this.changeArray(foo); // `changeArray` receives a *copy* of the reference
// held in `foo`; both references point to the same
// array
System.out.println(foo[0]); // Prints "Updated"
}
Passing a reference into a method is exactly like assigning it to another reference variable:
String[] foo = new String[3]; // Create a new aaray, assign reference to `foo` variable
String[] bar = foo; // Copy the reference into `bar` as well
foo[0] = "Hi there"; // Use the reference in `foo` to assign to the first element
System.out.println(bar[0]); // Use the reference in `bar`, prints "Hi there"
Essentially, references are values (numbers) that tell the JVM where the data for an object is. So even when we copy a reference (because Java is entirely pass-by-value, the value of the reference is passed to the function), it still points to the same memory as the original.
Since the reference is passed into the function by value, the function can't change the calling code's reference:
// A method that assigns a new reference; the calling code sees no change
void changeReference(String[] theArray) {
theArray = new String[1]; // Now we're not using the caller's object anymore
theArray[0] = "I was changed";
}
// A method that uses the above
void someMethod() {
String[] foo = new String[3];
foo[0] = "Original 0";
foo[1] = "Original 1";
foo[2] = "Original 2";
this.changeReference(foo);
System.out.println(foo[0]); // Prints "Original 0", our reference wasn't changed
}
You'll note that this is exactly how primitives are treated:
void whatever(int a) {
a = 5;
}
void someMethod() {
int foo;
foo = 3;
whatever(foo);
System.out.println(foo); // Prints 3, of course, not 5
}
...and in fact, object references (as opposed to objects) are primitives.
...should I declare a new string array or can I safely re-use same array that was holding the unfiltered array to hold filtered array
You can safely re-use it if that's appropriate within the scope of your function. It may be more appropriate to declare a new variable (e.g., filteredThingy), but that's a matter of style and will depend on the situation.
You probably can by it is very bad style and is very error prone and is very unsafe for future modifications.
Here is the example.
public void foo(String[] args) {
// do something with array.
args = new String[] {"a", "b"}; // reuse of the array.
// more code.
for (Sring s : args) {
// what will this loop get"?
// The answer is: a, b
// but will you remember this fact in a month if "more code" above is 50 lines long?
}
}
Passing objects is essentially passing references. E.g., your array will only exist in one place in memory when passing it between functions. Here's a runnable example illustrating that.
If you like you can reuse the same array in your routine. Note that changes made to that array will be visible to all objects sharing the same reference to that array. If that's not desirable then you must declare a new array.
String parentArray = {"S","B","R"};
// no need to use new operator to hold subSetArray.
String subSetArray = returnSubSet(parent);
public String[] returnSubSet(String[] _parent)
{
return Arrays.copyOfRange(_parent,1,2);
}
, when I pass a variable like array to
a function does it creates a new space
for the array in the heap each time I
pass it as parameter to further
functions or just it uses the same
space in the heap & just passes the
reference?
Answer
1. Object in Java are Pass by reference by value
2. when you pass an array to a function , a _parent variable will be created in stack and it points to the same Array Object in heap.
UPDATES: Primitive example
int global_scope_variable=10;
setValue(global_scope_variable);
public void setValue(int val)
{
// val is visible only within this method.
System.out.println(val); // output is 10
val=20;
System.out.println(val); // output is 20
System.out.println(global_scope_variable); // output is 10
}

Categories

Resources