Passing by reference ruining everything :( - java

Hey people i have this structure for the search tree
class State
{
//CLASS STATE
int value;
char[][] state; //the game Grid
State child[]; // children of current state, maximum is 8
State(char[][] src)
{
state=src;
child=new State[8];
}
this is the root node definition
State rootNode = new State(currentGrid);
rootNode.value=-1;
int v =maxValue(rootNode,depth);
after the end of recursion in the max value function the array in rootNode should not be edited since its the the first state but when i Display it i get an array filled with stuff which means that the rootNode.state passed by reference to the max value function :(
//i am trying to implement MiniMax Algorithm.

If you don't want objects that are passed as parameters to be changed, pass in a copy (or make a copy of the parameter inside the method).
Note that char[][] means you have an array of char arrays, i.e. you are working with objects and if you copy the first level you still might have a reference to the second.
Thus you might have to loop through the first level/dimension and copy all the arrays in there, like this:
char target[][] = new char[state.length][0];
for( int i = 0; i < state.length; ++i ) {
target[i] = Arrays.copyOf(state[i], state[i].length);
}

If you need, you can easily create a copy of the array through Arrays.copyOf
You can also create a deep copy. How to do this has been answered here: How to deep copy an irregular 2D array

Yes, Java passes references to arrays and not the array as a value. So if you give a reference to your internal state away, the receiver can change it and the change is "visible" in the source (in fact: it's only one array that has been changed and all reference holders will see the change).
Quick fix/solution: clone your state array and pass a reference to this clone instead of the original. This will keep your internal root state unmodified.

Related

Why replacing Objects (a class) with some arrays (primitive datatypes) in java reduce the run time significantly?

In my program I have a following class:
private static class Node
{
// True if '1', false otherwise (i.e. '0')
public final boolean isDigitOne;
// The number represented in the tree modulo the input number
public final int val;
// The parent node in the tree
public final Node parent;
public Node(boolean isDigitOne, int val, Node parent)
{
this.isDigitOne = isDigitOne;
this.val = val;
this.parent = parent;
}
}
I replaced this class with two arrays of following inside a method of another class.
boolean[] product0 = new boolean[num];
int[] product1 = new int[num];
The rest of the program is very similar, the class implementation creates an object when needed where as the array implementation allocate the maximum needed memory at the beginning of the execution.
I measure the run time on both cases.
I noticed for smaller values of num, the execution time is almost same. But for larger value, the array implementation runs much quicker.
Here is the comparison:
My question is Why array implementation runs faster?
The class implementation is available in the following link as "Answer 3"
How to find the smallest number with just 0 and 1 which is divided by a given number?
A big part of it will be due to the location of data in memory. Arrays of objects don't directly store data next to each other in memory, instead it stores a reference to the location of where the data is stored in memory. This means that after accessing the array's location and grabbing the data from the array, the system then has to grab the data from the location in memory the value of the array is pointing to. Arrays of primitive data, however, have the data directly stored in the array. This means the system only has to do one look up to access the array instead of two to access the array and then access an object. Systems usually work so fast that it's not significantly noticeable for smaller amounts of data but it can become apparent when the amount of data is increased.
Think of arrays as being like a linear organizer with boxes for all the data, with the array reference, you can just add the index to get to the relevant cube, and it directly contains the boolean or num value, so you can pull it out, do assignments and such very easily, since it's all right there.
This changes if you have an object, since that will be stored in a reference somewhere. That's like having an organizer with an address of another organizer somewhere else. So then you have to follow the address to do whatever you want to do. On top of that, once you get to that other organizer, it has to find the place where you wanted the data! This consumes more memory and more cycles as the memory grows.
TL;DR: arrays are faster because they take up a constant size and everything can be referenced explicitly by index. Objects are slower because they are typically stored as references to other places in memory and the offsets of class object must be computed implicitly by referencing the object property.

Not understanding Java bracket array correctly?

I was programming a plugin in Java and I wanted to set 4 different Location objects. Because in school(C++) they taught us to use [] and I like them (brackets), I decided to do that. Oh boy, I was wrong(or maybe it was just my mistake) I came up with this code:
Location[] pos = new Location[4]; //an array (I guess)
Location loc = e.getBlock().getLocation(); //to get the position of a block
and then I set it in a for loop to iterate trough them like this:
for(int i = 0; i < 4; i++){
pos[i] = loc;
}
But! When I wanted to change any of the pos[x] variables, all of them changed. Could this be related to pointers or something?
Anyways. I changed my code to do it like this
Location loc = e.getToBlock().getLocation();
Location loc1 = e.getToBlock().getLocation();
Location loc2 = e.getToBlock().getLocation();
Location loc3 = e.getToBlock().getLocation();
This code fortunately works, but how would I go with more variables, what if I wanted something like 200 of them? Or maybe a dinamic "array".
You might be wondering why I said "array" in quotes, but I really have no idea how to call pos[] other than an array, even tho I know that an Array exists and it's something completely different.
You have to create a new Location object at each iteration in the for loop.
Now you are using the same object in all the array slots. The 'loc' variable is a reference to the object in the heap, so changing it spreads the changes to all the array,
They all changed because you set them all to be the same object: the one you assigned to loc. If you had put the call to e.getToBlock().getLocation() inside the loop, your 4 array elements would have been different objects.
Right now your getLocation function is only being called once which creates a single object. Call it inside your for loop.
for (int i = 0; i < 4; i++) {
Location loc = e.getBlock().getLocation(); //to get the position of a block
pos[i] = loc;
}
When I wanted to change any of the pos[x] variables, all of them changed
It's because you assign each element of your pos to same object. You are from C++ background, so you should have a knowledge about pointers. What you are doing is assigining a "pointer" to same object in all positions of pos.
what if I wanted something like 200 of them?
I am not sure if I understand you right. You can use an ArrayList which allows you to add elements dynamically, so you don't have to know its size in advance. Look at the docs.
Did you intend to assign for all the array items the same object loc?
If yes, here we go. As others suggest, you should call the function e.getBlock().getLocation() once each time you go through your loop. This gives different objects with the same value.
Another workaround is to copy the object, rather than only assign the reference.
What I think about your problem is that you are mixing copying and assignment. When you assign loc to the array items in your loop
for(int i = 0; i < 4; i++){
pos[i] = loc;
}
you assign it by reference, as it an object and not a primitive data type.
This means that the array items, after you assigned loc, have a only a reference to a memory position, when you change its value via any reference, all other references will have the new value, expected behaviour.
If you intend to initiate all the items of your array to loc, you should deep/shallow copy it, i.e., not assign it by reference. See here for an explanation on difference between copy and assignment. Here is an answer for deep copy using serialization

mutate array in JAVA

public class example
{
public static void main(String[] args)
{
int[] MyArray = new int[10];
MyArray[1] = 5;
int[] NewArray = MyArray;
NewArray[1] = 10;
System.out.println(MyArray[1]);
}
}
Why does the system print out 10 instead of 5?
It seems like whatever changes we made to element in NewArray, MyArray will change along, why?
I copy this pattern to initiate like int, string variables but they don't behave like this above, why? thanks guy, I am new to CS programming.
It seems like whatever changes we made to element in NewArray, MyArray will change along, why?
You aren't changing NewArray. You're changing the array that the value of NewArray refers to. It's like this:
NewArray is a variable (an unconventionally named one, but hey)
The value of NewArray is a reference
The reference refers to an object
It's really, really important to differentiate between variables, references and objects. Don't feel worried that it didn't just come to you immediately - this is a stage a lot of people go through when they first encounter a language like Java.
The values of MyArray and NewArray both refer to the same array, so if you make changes to the array via one variable, you still see the change when you then look at the array via a different variable.
I copy this pattern to initiate like int, string variables but they don't behave like this above, why? thanks guy, I am new to CS programming.
For int, that's a value type - the value of an int variable is the number itself, not a reference to an object.
For String, I suspect you were changing the value of the variable to refer to a different String object - not changing the contents of the String object itself (which you can't - strings are immutable in Java). For example:
String x = "first";
String y = x;
x = "second"; // This doesn't change the value of `y`
I like to think of variables as pieces of paper. For value type variables, the value is just written on the piece of paper:
int i = 10;
is like having a piece of paper with the name i, and a value of 10 on it.
For classes and arrays (which are reference types) the value on the piece of paper isn't the object - it's a way of navigating to the object. A bit like having someone's home address written on a piece of paper.
Suppose you have two pieces of paper with the same address written on them. If you rub one of them out and write a different address, that doesn't change anything about what will happen if someone looks at the other piece of paper and goes to that house. That's like the String example above.
The array example, however, is more like this: I write my home address on two pieces of paper, and give them to Fred and Ginger. Fred reads the address, visits my home, and paints the front door red. (He's modifying the object - my house - without changing his piece of paper at all.) Now if Ginger reads the address on his piece of paper and visits my home, he'll see a red front door.
The reason this happens is because when you say int[] NewArray = MyArray; this is copying the reference of MyArray to NewArray.
This reason you are copying the reference is because you do not call the new operator to instantiate a new array.
So, when you say NewArray[x] it is pointing to the x position in memory of MyArray (and hence the value in memory of MyArray). No new memory is allocated when you do int[] NewArray = MyArray; since the new operator is not called.
It is beacuse when you do =, this makes the new obkect to point to the old one. So any changes made to the new one will reflect in the old one to, as they are the same technically.
You should array.clone to avoid this.
You are not copying it's value. You say:
Java create "MyArray".
Java creates a variable poiting at an object
Java create another array "NewArray" that is the same as MyArray
Java creates a variable poiting at the same object as MyArray
Java change the value of NewArray[1] to 10
Java changes the value on the object it is poiting at, not the variable itself.
Hope you get it.
As a side note, you should use [0] instead of [1]. Arrays start at 0, like everything in programming. So, the array with 10 items you created starts at 0 and ends at 9. Take note of that.

Is recursion with objects possible?

I have a class called Program which hold a grid. It has two methods possi() which saves all possible ways you can enter the grid and saves ArrayList possi with all possible entry points and method solve which actually goes and enters the grid with the provided entry point. I've done mazesolvers using dfs and bfs but there my problem is that solve actually changes the grid substantially usually bfs and dfs dont account for the maze being changed. That is why I am not using them. I want to got through all the possibilities of entry points and further points. My first level of entry points is stored in lev1.possi and I can loop through them. Then I have to create a new instance of a grid since solve will change the structure and apply the solve then return new possi from that new object. So essentially I am creating a new object for each change. The problem is grid.clone() isnt making a new object instead still refering to my old grid.
Program lev1 = new Program();//initializes grid randomly
lev1.possi();//calculates entry points and stores in possi
ArrayList<Program> lev = new ArrayList<Program>();//stores all possible objects
for (int i = 0; i < lev1.possi.size(); i++)//loops through all entry points
{
Program pick = new Program(lev1.grid.clone());//makes a new object
lev.add(pick);
lev.get(i).solve(lev1.possi.get(i));//changes the new object
lev.get(i).possi();//calculates further points to go through
}
I assume grid is some complex type, which contains complex types like an array, etc. In this case clone() does not create a deep copy (i.e. it does not recursively clone the parts like an array).
Here is an example of a clone() method for complex types: In this example we have a type FlightLogEntry which contains a TreeMap. To clone a FlightLogEntry we need to create a new TreeMap and fill the map using the original elements. In this example those elements are not cloned (clone.setAttendant(p, this.attendats.get(p)). If you need an even deeper copy from the clone method (which depends on the usage of the clone) you might want to clone the attendat also like this: clone.setAttendant(p, this.attendats.get(p).clone().
#Override
public FlightLogEntry clone() {
FlightLogEntry clone = (FlightLogEntry) super.clone();
clone.attendants = new TreeMap<Person, Duty>();
for( Person p : this.attendants.keySet() ) {
clone.setAttendant(p, this.attendants.get(p));
}
return clone;
}
You need to instantiate a new grid object in your Program(grid) constructor, then assign the values from the old grid with the new one.

Java get an element from an array, edit it, then store it in another array, without altering the first array

I have encountered a problem in one of my Java projects, which causes bugs.
The problem sounds as following:
I have two arrays. Let's name them firstArray and secondArray. Object in this case is a seperate class created by me. It works, the array can be filled with objects of that type.
Object[] firstArray= new Object[];
Object[] secondArray = new Object[];
Now, when I get an element out of the first array, edit it and then copy it in the second array, the object from the first array gets altered too.
tempObj = firstArray[3];
tempObj.modifySomething();
secondArray[3] = tempObj;
Whenever I do this, the (in this case) 3rd element(actually 4th) of the first array gets the modifications. I don't want this. I want the first Array to remain intact, unmodified, and the objects I have extracted from the first array and then modified should be stored in the second so that the second array is actually the first array after some code has been run.
P.S. Even if I get the element from the first array with Array.get(Array, index) and then modify it, the element still gets modified in the first array.
Hopefully you understood what I wanted to say, and if so, please lend me a hand :)
Thank you!
You're going to have to create a new object.
The problem is the modifySomething call. When you do that, it alters the object on which it's called. So if you've only got one object (even by two names), you can't call modifySomething or they will both change.
When you say secondArray[3] = firstArray[3], you aren't creating a new object: you're just assigning a reference. Going through an intermediate temporary reference doesn't change that.
You'll need code that looks like this:
Object tempObj = firstArray[3].clone();
tempObj.modifySomething();
secondArray[3] = tempObj;
The clone() method must return a new object divorced from the original but having identical properties.
When you retrieve an element from your array, you have a reference to it. So if you modify it, the modification are shered through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new Object and use its constructor to initialize its fields.
The object extracted from the first array needs to be cloned to create a new instance that is seperate. Otherwise the modification will affect the object in the first array as it is the same object.
When you retrieve an element from your array, you get a reference to it. So if you modify it, the modification are shared through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new method which take in input your retrieved object and return a new one alike.
In Java, when you do this secondArray[3] = tempObj;, you actually put the reference to the array, not the real object
So firstArray[3] and secondArray[3] point to the same real object
What you need to do is to create a new object that is identical to your original object, and put the reference of the new object to your secondArray
It might worth to point out that default clone() function only does a shallow copy, so if you have mutable objects in your object's fields, it might cause some problems. Take a look at this article about how to do a deep copy

Categories