How to prevent the value of an array from changing - java

In my program, I am declaring a static int 2D array and setting it equal to some values. In a different method, I create a local variable and assign it to the 2D array I created. I make some changes to the local variable, however I don't want my initial values in my 2D array to change.
The reason I am using static is because I am using a static main method and I figured all other methods and variables had to be static as well.
Here's a simple layout of what I am doing
public static int[][] myArray = {{1,2},{3,4}};
public static void main(String args[]){
doSomething();
}
public static void doSomething(){
int[][] newArray = myArray;
//do Something to newArray
}
I do not want the values of myArray to change is there a way to handle this? Do I have to get rid of a static variable within a static method?

You will have to create deep copy of your array. You can do it manually or use System.arraycopy() to suit your needs.

Arrays are mutable and so you need to use System.arraycopy to make defensive copies. Make the array private and call a public method which hands a copy is the way to prevent mistakes of bugs by sharing a reference when you must not.

Deep copy the original one and keep one of these two arrays (only making change to one of them

Try:
int[][] newArray = Arrays.copyOf(myArray, myArray.length)

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() {}
}

Array as attribute in an object [duplicate]

This question already has answers here:
How do I do a deep copy of a 2d array in Java?
(7 answers)
Closed 4 years ago.
I'm relatively new to Java, and I just learned this
import java.util.Arrays;
public class Foo {
private int[][] foo;
public Foo(int[][] arr) {
this.foo = arr;
}
#Override
public String toString() {
return Arrays.deepToString(this.foo).replace("],", "],\n");
}
public static void main(String[] args) {
int[][] p = { { 0, 0 }, { 0, 0 } };
Foo g = new Foo(p.clone()); // doesn't work with p nor p.clone()
System.out.println(g);
p[0][0] = 1;
System.out.println(g);
}
}
Here I create an object with a reference to another object, and I can alter the object from the outside since I have the reference to the thing I just passed as an argument to the constructor.
This, although I understand why it happens, seems counterintuitive to me. If I save something as an attribute of an object I expect the object to have a “private” copy not accessible outside.
And I tried with .clone() and doesn't solve it. So the question is...
How is this usually done? Do I need to write a few for loops inside the constructor to get every value out of the argument?
 (Or is this a non-issue?)
This last part of the question is important, may be this is a non-issue. Or do people do “something” (a few loops to get a deep clone)?
The problem here is that java doesn't really have 2-D arrays. This:
int[][] x;
is an array of int arrays. It is not a 2D int array, though of course an array of int arrays does feel a lot like a 2D array. For most intents and purposes it iS a 2D int array, unless it isn't, and with clone, it isn't. The clone() impl of an array makes a new array and just copies each and every value, verbatim, into the new array. Which means that your array of int arrays is cloned, but the inner int arrays are not.
When treating int[][] as 'this is a 2D array', yeah, that is unintuitive. When treating int[][] as 'an array of int arrays', it is quite intuitive. You wouldn't expect an array of arraylists, when cloned, to also clone each individual arraylist either.
Soo.. how do you deep-clone an array of arrays (of arrays of arrays)? See How do I do a deep copy of a 2d array in Java? for lots of options :)

Is a final array of final strings still mutable?

Suppose I have an array
public static final String[] fooArray ={ Foo.a, Foo.b, Foo.c };
where Foo.a b and c are static final Strings.
Could I still do something like fooArray[0] = "taco"; and end up with { taco, Foo.b, Foo.c } as the contents of fooArray?
If so, would making the array private, and having a getter that makes a copy of the array using Arrays.copyOf solve this issue?
The final applies to the array reference, not its entries. Different strings can still be written to its entries.
If so, would making the array private, and having a getter that makes a copy of the array using Arrays.copyOf solve this issue?
Yes, defensive copies are a fairly standard way to handle this.
Alternately, given what you've outlined, you don't need to have the array at all, just a getter that looks like this:
public String[] getFooArray() {
return new String[] { Foo.a, Foo.b, Foo.c };
}
Or as jtahlborn commented, use an unmodifiable List<String>:
public static final List<String> fooArray;
static {
List<String> a = new ArrayList<>();
Collections.addAll(a, Foo.a, Foo.b, Foo.c);
fooArray = Collections.unmodifiableList(a);
}
// (There's probably some really nifty Java8 way to do that as a one-liner...
Yes.
A final array means you can't reassign the array.
So you couldn't do: fooArray = new String[]{...};.
But you can however change what is inside the array. This is the effect of saying: "You can't change the box, but you can change the apples inside the box to be oranges." The box stays the same, and is final, but you've effectively changed the contents.
That being said, if you encapsulate the class, then you can just clone the array when it is needed.
This is currently employed by many classes, such as String#toCharArray and Enum#values, where changing the array's contents comprises the integrity of the finalized object(s).
The final-modifier will only prevent changing the fooArray-reference, not the contents of the array itself. Making it private and having a getter returning a copy would hide the original array, and any changes made to the returned array would only affect the copy. However, it would still be possible to modify the original via reflection, but if your intent is to only prevent accidental modification of the original array, that would work.
Rest have answered about the final well. Just a suggestion on the other part - rather than implementing a getter which does a copy of entire array, if your scenario allows, its better to have a getArrayElement(int position) where you just return an array element rather than the whole array - copying an array is expensive.
You could make a getter that returns a mutable copy of an immutable value.
If you used array copy the values inside the copy will still be final.
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
final int b = 5;
int c = b; // Because of c being mutable we can now change this copy
c = 7;
System.out.println(c);
}
}
... Some psudo code -> for copying an iterable into a mutable form.
public collection<int>(final collection<final int> finalCollection )
collection nonFinalCollection = new collention();
for(k : finalCollention){collection.add((int) k)}
return(collection)

Using an existing array in another class

Let's change the way I am asking the question. For constructing an object in a class, we can also use some other variables. Consider this example:
public class Foo {
int X1;
int X2;
public Foo(int a) {
int[] array=new int[4];
// ...
}
}
If we create 2 objects of this class, we will have 2 variables per object and totally the memory will be occupied for 4 integer variables. My concern is the memory dedicated to the integer array defined inside the constructor. How the memory will be assigned when creating several objects?
Thanks,
To answer your first question, yes. If you create an array in the main method of one class, then you create the same array again in the constructor of another class, then there will be two copies of that array in memory. More importantly, if you later modify one copy, the other copy will not be modified.
The best way to solve your problem is to pass the array into the constructor as a parameter. Then, you'll be able to access (and even modify) elements of the original array. For example:
public class Driver{
public static void Main(String[] args){
int[] array = {1, 2, 3};
CustomObject otherObject = new CustomObject(array);
}
}
//And, in a different file....
public class CustomObject{
public CustomObject(int[] array){
int x = array[0];
//etc..
}
}
If you have two references to the same object there won't be any useless memory usage.
For better understand how it works, look at the difference between stack and heap memory in Java
(Basically, your array in main method and the array defined in the class's constructor point to the same memory area)

How to copy hashset and hashmap, and does the Java use pointers?

I have two questions:
First:
I have a function which returns a HashMap. To read the returned value, I write it like this:
HashMap<Integer,String> hs=my_func2();
I do the same if the function returns a HashSet.
HashSet<Integer> hs=my_func();
I wanted to know if in this way the returned value is copied into hs, or I should write a deep copy for it or I should write it like this:
HashSet hs=new HashSet(my_func());
HashMap hm=new HashMap(my_func2());
Second quesion:
I make a matrix by calling make_matrix_funciton. matrix woule be a 2-dimensional array containing:
[0 1 1
0 0 0
0 0 0]
Then I give this matrix to sort_vec, and in this function the elements of matrix change. I think java is not pointer based, so when I come out of sort_vec, matrix should be as it had been. But, it has changed! It is
[0 0 0
0 0 0
1 1 0]
which shows the changes that had been applied to it inside the sort_vec function. Is it normal and if yes, what should I do to prevent it. The code below is compilable.
public static void main(String args[]) {
int matrix[][]=new int[3][3];
matrix=make_matrix("011000000");
int indexes[]={2,1,0};
int[][] mat=sort_vec(3,matrix,indexes);
}
private static int[][] sort_vec(int motifsize,int [][]mat,int[] indexes)
{
int[] main_index={0,1,2};
int l=indexes.length;
for (Integer i=0;i<l;i++)
if(indexes[i]!=main_index[i])
{
int j=indexes[i];
int k=main_index[i+1];
for(;k<l;k++)
if(indexes[k]==main_index[i])
break;
indexes[k]=j;
mat=exchange(motifsize,mat,j,main_index[i]);
}
return mat;
}
private static int[][] exchange(int motifsize,int [][]matrix,int x,int y)
{
int temp;
for(int i=0;i<motifsize;i++)
{
temp=matrix[i][x];
matrix[i][x]=matrix[i][y];
matrix[i][y]=temp;
}
for(int i=0;i<motifsize;i++)
{
temp=matrix[x][i];
matrix[x][i]=matrix[y][i];
matrix[y][i]=temp;
}
return matrix;
}
private static int[][] make_matrix(String id)
{
int matrix[][]=new int[3][3];
int c=0;
for(int x=0;x<3;x++)
for(int y=0;y<3;y++)
{
if(id.charAt(c)=='1' || id.charAt(c)=='5')
matrix[x][y]=1;
c++;
}
return matrix;
}
Java always passes Objects by reference, so if you return a HashMap-Object from a function, the reference will be passed to the hs variable in your example. Passing the HashSet to the constructor of a new HashSet instance will not work. It will create a new HashSet with the same object references as in the original one. If you modify one of these objects, the change will appear on all other reference points, too.
If you want to totally detach the copy, you will need your own method for deep copying because in the JavaDoc for the clone() method it says:
Returns a shallow copy of this HashSet instance: the elements themselves are not cloned.
The same goes for arrays. Every array is an object, so if you modify an element, it will be modified for all references to this array. To create a deferred copy, use System.arrayCopy
You are misunderstanding how Java's references work.
In the first part, your object will be a reference to a HashMap - i.e., whatever object you've returned from the function
In the second part, you are passing a reference to an int[][], it is not pass by value when it's an array of primitives. Thus, your function will modify the array. If you want a function that does not modify the input array, you need to copy what is passed in to the function or you will need to copy the array before you pass it to your function.
The behavior in Java sorting routines is that they modify the original array.
In sum, there is no way to 'pass by value' an object or array in Java. If you want this behavior, you have to clone (e.g., copy) the object manually or using #user3001's suggestion
Once you figure this out, you may want to read this as well: http://javadude.com/articles/passbyvalue.htm

Categories

Resources