Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent changing the value of array or object

Tags:

java

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?

like image 500
Ophelia Avatar asked Mar 30 '19 04:03

Ophelia


2 Answers

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.

like image 168
Aniket Sahrawat Avatar answered Sep 29 '22 01:09

Aniket Sahrawat


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

like image 24
Stephen C Avatar answered Sep 29 '22 03:09

Stephen C