Java Heap and Pass By Value - java

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.

Related

How to prevent changing the value of array or object

I am a beginner in Java. When developing a program, I created an object with a constructor with variables as arguments. But when I change the value of the variable after creating the object, my object has the second value instead of the first one. I don't want my object to change the value. What do I do?
public class Person {
public Person(int[] arrayTest) {
this.arrayTest = arrayTest;
}
public int[] getArray() {
return this.arrayTest;
}
public boolean canHaveAsArray(int[] arrayTest) {
return true;
}
private int[] arrayTest = new int[2];
public static void main(String[] args) {
int[] array = new int[] {5, 10};
Person obj1 = new Person(array);
array[0] = 20;
System.out.println(Arrays.toString(obj1.getArray()));
}
}
My output should be [5, 10], but instead, I am getting [20,10]. I need to get [5,10] even when I change an element of the array as shown above. What should I do?
If you pass the original array to the constructor of Person, you are passing the reference to the original array. So any change in arrayTest inside Person instance will reflect in original array(int[] array) and vice-versa.
If you don't want to change the value of elements of original array in Person instance then you have two options:
You can modify the code in Person constructor to create a copy of original array using java.util.Arrays.copyOf method and then use that copy:
public Person(int[] arrayTest) {
this.arrayTest = java.util.Arrays.copyOf(arrayTest, arrayTest.length);
}
Don't pass the original array to constructor, instead just send a copy of original array:
Person obj1 = new Person(java.util.Arrays.copyOf(array, array.length));
However, I would prefer first approach.
If you would like to prevent the value of variable which is of primitive type, you can do so using final keyword. Eg:
private final int test = 1;
To prevent changing the value inside an object you can mark the fields as final. A final keyword in declaration of object instance means the variable can't be reassigned and doesn't guarantee that the object state won't change if the reference to that object is shared. To prevent changing the state of a particular object, you should mark it's field as final.
There is no such thing as immutable (unchangeable) array in Java. The Java language does not support this. As JLS 4.12.4 states:
If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.
The JVM spec doesn't support an immutable array type either. You can't solve this at the language level. The only way to avoid changes to an array is to not share the reference to the array with other code that might change it.
In your example, you have what is known as a leaky abstraction. You are passing an array to your Person class, and the caller is keeping a reference to that array so that it can change it. To solve this, you can:
copy the array, and pass a reference to the copy, or
have the constructor (or a setter for the array attribute) make the copy.
(See answer https://stackoverflow.com/a/55428214/139985 for example code.)
The second alternative is preferable from an OO perspective. The Person class should be responsible for preserving its own internal state from interference ... if that is your design requirement. It should not rely on the caller to do this. (Even if the caller is technically part of the same class as is the case here.)
There is no unmodifiable array, but you can make an unmodifiable list:
List<Integer> list = List.of(5, 10);
You will have to change your code to use lists instead of arrays, but this is generally preferable anyway.
If you already have an array of a non-primitive type, you can wrap it in an unmodifiable list, like so:
List<Integer> list = Collections.unmodifiableList(Arrays.asList(array));
However, while you can't change the list directly, changing the array will change the list. Moreover, this won't work on int[], but only on subclasses of Object[].
In Java, objects/arrays are manipulated through reference variables#
When a function is invoked with arrays as their arguments, only a reference to the array is passed. Therefore, when you mutate array array, the arrayTest field also get mutated as they are referring to the same address
To override this behavior, you can create a copy of the array in your constructor using Object.clone() method like:
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone();
}
# Source: Wikipedia
Instead of passing a copy of the array to the object, as others have suggested, I would recommend that the Person object's constructor should create a copy. Which means instead of,
this.arrayTest = arrayTest;
It should be
this.arrayTest = Arrays.copyOf(arrayTest, arrayTest.length);
This would allow the object to be defensive against malicious code trying to modify arrays after construction and validation by constructor. In fact most IDEs have analysis tools which will give you a warning against saving array reference.
As others have already pointed out: The array is passed as a reference to the Person. So changes that are later done to the array will be visible to the Person object. But that's only one half of the problem: You are not only passing a reference to the array to the constructor of the Person, you are also returning a reference from the getArray method.
Generally speaking, and as StephenC already pointed out in his answer: One important aspect of Object-Oriented design is to properly manage the state space of objects. It should not be possible for users of a class to bring an object into any form of "inconsistent state".
And this is difficult with plain primitive arrays. Consider the following pseudocode, referring to the class that you posted:
int originalArray[] = new int[2];
originalArray[0] = 12;
originalArray[1] = 34;
Person person = new Person(originalArray);
int arrayFromPerson[] = person.getArray();
originalArray[0] = -666; // Modify the original array
System.out.println(arrayFromPerson[0]) // Prints -666 - this is unexpected!
arrayFromPerson[1] = 12345678; // Modify the array from the person
System.out.println(originalArray[1]) // Prints 12345678 - this is unexpected!
Nobody knows who has a reference to the array, and nobody can verify or track that the contents of the array is not changed in any way. How critical this is becomes more obvious when you anticipate that the Person object will be used at different places, possibly even by multiple threads.
Plain primitive arrays in Java do have their justification. But when they appear in the interface of a class (that is, in its public methods), they should be view with scrutiny.
In order to be absolutely sure that nobody can interfere with the array that is stored in the Person object, you'd have to create defensive copies everywhere:
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone(); // Store a clone of the array
}
public int[] getArray() {
return this.arrayTest.clone(); // Return a clone of the array
}
But this may be cumbersome. A more object-oriented solution could be to expose a "read-only view" on the state that is represented with the array. For example:
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone(); // Store a clone of the array
}
public int getArrayLength() {
return this.arrayTest.length;
}
public int getArrayElement(int index) {
return this.arrayTest[index];
}
(Of course, in practice, you'd name the methods accordingly, depending on what the array actually represents. For example, if it's the ages of the children of the person, you'd call the methods getNumChildren() and getAgeOfChild(int i) or so...)
Another option how this can be solved is to expose an (unmodifiable) List view on the array. This can, for example, be done with the asUnmodifiableList method that is shown in this answer.
as you are beginner in java you write following code in constructor but it is better to use clone method as marco13 and rv 7 already explained
and as sourabh bhat explained we can also use Arrays class copyof
the idea behind all of above logic is simple don't pass referance of current object but create clone of object and pass that clone or just copy each content of the object
public Person(int[] arrayTest) {
for (int i = 0; i <this.arrayTest.length; i++) {
this.arrayTest[i]=arrayTest[i];
}
}
Here is what happens in memory:
Program: Stack memory: Heap memory:
int[] array = new int[] {5, 10}; array -> 0x77a89 0x77a89 {5, 10}
Person obj1 = new Person(array); obj1.arrayTest -> 0x77a89 No change
array[0] = 20; 0x77a89 {20, 10}
As you can see stack memory holds only the address of the object which gets created in the heap memory. So when you change the arrays value it automatically changes in the Person obj1 object as well.
To fix this you need to create a new Object in memory so that the actual Objects value is copied. To do this we can:
[1] Use the clone property of array.
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone();
}
[2] Or we can create our own clone.
public Person(int[] arrayTest){
if (arrayTest == null){
this.arrayTest = null;
} else {
int[] copyArray = new int[arrayTest.length];
for(int i=0; i<arrayTest.length; i++) {
copyArray[i] = arrayTest[i]
}
this.arrayTest = copyArray;
}
}
Either way a new Object is created in memory and this prevents the object from being shared.
Edit 5/5/19: Source code added
As most answers point out, there is no immutable array of primitives in Java. So you have to do some tricks.
Pure Java: Make defensive copies. Most answers show how to store a copy of the array that is received as a parameter in the constructor. But only one answer mentions that you also have to return a copy of the internal array with getArray().
public class Person {
final private int[] arrayTest;
public Person(int[] arrayTest) {
this.arrayTest = java.util.Arrays.copyOf(arrayTest, arrayTest.length);
}
public int[] getArray() {
return java.util.Arrays.copyOf(arrayTest, arrayTest.length);;
}
}
Other internal representation: Store the array as a (mutable) ArrayList, which is based on an array and should have best performance. You have to convert from array to List in the constructor and from List to array in getArray(). There is no need to use Collections.unmodifiableList() (or Guavas ImmutableList<>) as long as you write no method that could modify the List because no one will have access to the List.
public class Person {
final private List<Integer> arrayTest;
public Person(int[] arrayTest) {
this.arrayTest = new ArrayList<>(Arrays.asList(arrayTest));
}
public int[] getArray() {
return this.arrayTest.stream().mapToInt(Integer::valueOf).toArray;
}
}
Let other people do the job. Google AutoValue auto-generates immutable classes. And provides equals(), hashCode() and toString(). Easy to use. My favorite solution.
import com.google.auto.value.AutoValue;
#AutoValue
public abstract class Person {
public static create(int[] arrayTest) {
return new AutoValue_Person(int[] arrayTest);
}
public abstract int[] getArray() {}
}

Copy constructors instead of Clone in java

I am trying to implement a copy constructor in java. I am facing a problem with non primitive type fields of the class. While creating a new copy, it is sharing the members. For Example
public class Bad implements Cloneable {
private ArrayList<Integer> a;
private Object c;
public static void main(String[] args) {
Bad b1 = new Bad();
b1.a.add(10);
System.out.println(b1.a);
Bad b2 = b1.clone();
b2.a.add(12);
System.out.println(b1.a);
}
Bad() {
a = new ArrayList<>();
c = null;
}
Bad(Bad b) {
a = b.a;
c = b.c;
}
public Bad clone() {
return new Bad(this);
}
}
And the result is :
[10]
[10, 12]
I don't want this to happen. Take this as an example. My original problem consists of even more fields that are user defined.
Or are there any libraries which do the work for me? Thanks in advance.
Simple rules for a copy constructor:
primitive values may be copied as-is; they are just values without a separate identity
references to immutable types (eg. String, Integer, any enum class constant) may also be copied as-is; although the original and the copied objects will share the same reference, the referred object is immutable and will never change
references to mutable types (eg. Date, ArrayList, any array) must be copied to a new instance of the type; otherwise the original and the copied object will share a reference to the same mutable field object (which is not what you want)
Making a copy of an object that contains only fields with primitive and immutable values is easy mode.
Copying an object whose fields contain mutable objects can make the process arduous and expensive depending on how complex the mutable object is (imagine an ArrayList that contains a Map whose values are also Maps). Making a new copy of the mutable field is, however, essential if you wish to have a safe copy.
Integer is immutable but you need to create a totally new ArrayList, and I mean here :
Bad(Bad b) {
a = b.a;
c = b.c;
}
do instead
Bad(Bad b) {
a = new ArrayList<>(b.a);
c = // this here must be copy constructed too
}
and then you will get
[10]
[10]
The correct way would be creating a new instance of the list instead of passing a reference to the original list.
Bad(Bad b) {
a = new ArrayList<>(b.a);
c = b.c; // this should call clone or something similar as well
}
Also note that if you would have some non-primitive type within the list of b.a, then you would have to copy/clone all the sub-elements as well (it is not needed now as you have Integer in it which is not mutable).

Workaround for passing by reference in java

From this book:
Find the kth to last element of a singly linked list.
One of the proposed solutions is as follows:
public class IntWrapper{
public int value = 0;
}
Node nthToLast3(Node head, int k, IntWrapper i){
if (head == null){
return null;
}
Node node = nthToLast3(head.next, k, i);
i.value = i.value + 1;
if (i.value == k){
return head;
}
return node;
}
Why do we have to create the int Wrapper class and can't we use an int directly?
What this trick does, is to wrap an int (native type) in an object (Object derived type). Everything is passed by value in Java, and for objects, the value of the reference is passed as an argument, in a sense (think of it like a pointer value in C/C++, for example).
It is impossible in Java to pass primitive values by reference. This is a restriction on the language itself.
Technically, the only things you can pass into methods are "primitives, and pointers to objects". The latter also being a form of primitive. Java possesses neither references nor const object passing.
The author uses IntWrapper instead of an int because he wants to achieve persistent state for a value between the callers and callees.
A modification to the int member of an IntWrapper instance in a callee will be visible to a caller.
With a plain int, that's not possible because it's a primitive type, and hence it will be passed by value (it will be 'copied' if I may).
The point is that you want to be able to set the value of i.
ints are in Java implemented as primitive data, they are passed-by-value. This means that the following code doesn't set a:
public void Foo () {
int a = 5;
System.out.println(a);//prints 5
setA(a);
System.out.println(a);//prints 5
}
public void setA (int a) {
a = 3;
}
Java copies the value of the variable on the stack and the copy is modified leaving the original a untouched.
By using a Wrapper, you store the int in an object. Since objects are passed-by-value from a "variable perspective", or passed-by-reference from the objects perspective, you refer to an object that contains an int. In other words, aw referers to the same instance. Because you copied the reference an not the object. Changes made by the callee are thus reflected in the view of the caller.
public void Foo () {
IntWrapper aw = new IntWrapper();
aw.value = 5;
System.out.println(aw.value);//prints 5
setA(aw);
System.out.println(aw.value);//prints 3
}
public void setA (IntWrapper aw) {
aw.value = 3;
}
This is a useful hack in Java when you want to return multiple values or modify a variable of the caller.
C# alternatively provides the ref keyword, that enable call-by-reference for primitive values.

pass by reference/value - simple example

I know this issue has been addressed many times - but my Java/C++ knowledge is so weak I can barely understand the answers :-( ... what I'd really like is just a super simple example.
In C++ I could write the following:
void func()
{
int x = 3;
add_one(x);
// now x is 4.
}
void add_one(int &var)
{
var++;
}
What I'd like to see now is the simplest way to achieve the same effect with java.
You can't directly. The closest you can get is to put the value in an object, and pass the reference (by value, so the reference gets copied) into the method.
void func()
{
int x = 3;
int[] holder = [x];
add_one(holder);
// now holder[0] is 4. x is still 3.
}
// container here is a copy of the reference holder in the calling scope.
// both container and holder point to the same underlying array object
void add_one(int[] container)
{
container[0]++;
}
Here I use an array, but the wrapper can be any object.
In java method arguments are pass-by-value, and can't be changed in the function. You must wrap the int - or any other primitive type - in an Object or an array. Passing an Object or an array as a method argument passes a reference which can be used to modify the object.
Java already has Object based wrappers for primitive types, e.g. Integer, but these are immutable by design. Some libraries provide mutable versions of these wrappers; you can also create your own:
public class MutableInt
{
private int val;
public MutableInt(int val)
{
this.val = val;
}
public void setValue(int newVal)
{
this.val = newVal;
}
public int getValue()
{
return this.val;
}
}
void func()
{
int x = 3;
MutableInt wrapper = new MutableInt(x);
add_one(wrapper);
}
void add_one(MutableInt arg)
{
arg.setValue(arg.getValue() + 1);
}
You cannot do this. Java is only pass by value. Primitives are obvious, but the thing that's passed for objects is a reference, not the object itself.
As you can see from the other answers, Java is purely pass by value. Objects are passed by what some call "value-reference". Since an object in java is simply a pointer reference, you can think of the "value" as the address where the object lives on the heap. So when you make a method call, you're copying the "value", aka address, to the method parameter:
Object x = new Object();
foo(x);
During object creation
Heap --> allocate Object (5000)
Variable Declaration
Stack --> allocate local variable (1000)
Variable Assignment
Stack address 1000 set to 5000 (to point to object instance)
So you can see that there are two separate memory allocations here. The "value" of the variable is considered to be it's address on the heap.
Method Call
Stack --> allocate method parameter 8000
Stack address 8000 set to same value as passed parameter 5000
This is why if you reassign an object instance in a method, it does not propagate back to the caller. You would have changed the heap location at stack location 8000. And the calling method's stack location 1000 still has the value 5000 (the original object instance).
Think of it like this in C:
void method(myobject * obj);
You can certainly change fields of "obj", and you can do this locally:
obj = new myobject();
But the caller will still see the original value it passed.
Java has no analog to the & reference operator.
And there are built in classes which can be used for the your purposes. AtomicInteger, AtomicLong, etc... are mutable, though you may suffer a performance hit due to synchronization involved.
I would recommend a generic ValueHolder class to account for all situations where you want to simulate pass by reference:
public class ValueHolder<T> {
private T value;
// getter/setter/constructor
}
Java allows copy by reference for objects and copy by vlaue for primitive types (int,float,etc..). This is so by default and is not subject to change. If you need to change the value of an int inside a function, then you can use the class Integer for example
public int getOneMore(int val) {
return val + 1;
}

Why when I pass an array, it changes value in the method? Amazing [duplicate]

This question already has answers here:
Changing array in method changes array outside [duplicate]
(2 answers)
Closed 3 years ago.
public class Test {
public static void main(String[] args) {
int[] arr = new int[5];
arr[0] = 1;
method(arr);
System.out.println(arr[0]);
}
private static void method(int[] array)
{
array[0] = 2;
}
}
After invoking method, arr[0] becomes 2. Why is that!?
You can call set methods on objects passed to a method. Java is pass by value, which means that you can't replace an object in a method, though you can call set methods on an object.
If Java were pass by reference, this would pass:
public class Test {
public static void main(String[] args) {
Test test = new Test();
int j = 0;
test.setToOne(j);
assert j == 1;
}
public void setToOne(int i) {
i = 1;
}
}
Java is Pass-by-Value, Dammit! http://javadude.com/articles/passbyvalue.htm
This is because Java uses Call by Object-Sharing* (for non-primitive types) when passing arguments to method.
When you pass an object -- including arrays -- you pass the object itself. A copy is not created.
If you mutate the object in one place, such as in the called method, you mutate the object everywhere! (Because an object is itself :-)
Here is the code above, annotated:
public static void main(String[] args)
{
int[] arr = new int[5]; // create an array object. let's call it JIM.
// arr evaluates to the object JIM, so sets JIM[0] = 1
arr[0] = 1;
System.out.println(arr[0]); // 1
method(arr); // fixed typo :-)
// arr still evalutes to JIM
// so this will print 2, as we "mutated" JIM in method called above
System.out.println(arr[0]); // 2
}
private static void method(int[] array)
{
// array evaluates to the object JIM, so sets JIM[0] = 2
// it is the same JIM object
array[0] = 2;
}
Happy coding.
*Primitive values always have call-by-value semantics -- that is, a copy is effectively created. Since all primitive values are immutable this does not create a conflict.
Also, as Brian Roach points out, the JVM only implements call-by-value internally: the call-by-object-sharing semantics discussed above are implemented by passing the value of the reference for a given object. As noted in the linked wikipedia article, the specific terms used to describe this behavior differ by programming community.
Additional:
Pass by value or Pass by reference in Java? -- see aioobes answer and how it relates with Brian Roachs comments. And aioobe again: Does array changes in method?
Make copy of array Java -- note this only creates a "shallow" copy.
Because that's exactly what you're telling it to do. Java passes first by value, then by reference. You're passing in the array, but any modifications you make to that array will be reflected on any other accesses to that array.
A quick example for thought:
If within method you did array = null, no change would be visible from main - as you would be changing the local value of array without modifying anything on the reference.
Because when you are passing argument like int/double/char etc. they are the primitive data types and they are call by value - meaning their values are copied to a local variable in this method (that has the same name as the names in your argument) and changes made to them are only changes made to these local var -> does not affect your primitive type variables outside the method
however an array or any object data type is called by reference -> the argument pass their address(reference) to method. that way, you still have a local variable named by them which has the reference. You can change it to reference another array or anything. but when it is referencing an array, you can use it to set the value of the array. what it does is accessing the address it is referencing and change the content of the referenced place
method(arr[0]);
I think that's supposed to be
method(arr);
But anyway the value passed as argument to the method is the reference to the array and the local variable arr in the method is referencing the same array. So, within the method you are making changes to the same array.
Java is pass by value. What confuses people is that the 'value' of a variable that refers to an object allocated on the heap is a reference, so when you pass that, you pass the reference 'by value' and therefore it refers to the same object on the heap. Which means it doesn't matter from where you modify the referent; you're modifying the same thing.

Categories

Resources