Object clone() in Java: why does this assertion fail? - java

From what I know, object clone() creates a new copy of the cloned object. In my case I'm trying to clone the matrix of Symbol (which is a simple enum). this.table is the original object, while t is the clone. When I write a new value into a cell of t I would expect that this.table remains unchanged. However this is not the case and the second assert fails. (I added the first assert only to ensure the correctness of the second one).
Here is the code:
#Override
public State applyAction(Action action) {
int x = ((TickAction)action).x;
int y = ((TickAction)action).y;
Symbol[][] t = this.table.clone();
assert this.table[x][y] != currentPlayer.getSymbol();
t[x][y] = currentPlayer.getSymbol();
assert t[x][y] != this.table[x][y] ;
TableState ts = new TableState(t,this.currentPlayer.getNextPlayer());
ts.setLastAction(action);
return ts;
}
Note: with debugger I checked that t and this.table actually have different id, however after a second check I noticed that, despite this, their single cells have the same id. Then I'm much confused about this. Could someone explain me what's happening?

You have an array of arrays of Symbol instances.
When you call clone() on this.table, you get a new array, t, but each of the arrays in t is the same as the array in this.table.
In order to check that, you can try assert t[0] == this.table[0];.
In order to get a deeper clone, you would have to create a new array and initialize it yourself:
Symbol[][] t = new Symbol[][this.table.length];
for (int i = 0; i < t.length; i++)
{
t[i] = new Symbol[this.table[i].length];
for (int j = 0; j < t[i].length; j++)
{
// Here I am sharing the Symbol objects between the two arrays.
// If you do not want that, define your own way to copy or clone the object.
t[i][j] = this.table[i][j];
}
}

I'm just guessing here, but Java makes a distinction between == and .equals() and everyone gets burned once or twice using == with some object reference that actually needs .equal. Give this a try...
assert this.table[((TickAction)action).x][((TickAction)action).y].equals( currentPlayer.getSymbol() );

you cant use clone as is, it wont help you if you did not implemented it yourself.
same for equals(except strings)

Related

How can you create an object, set it exactly equal to another object, and modify it without affecting the old object inside of a loop?

It's hard to explain what my problem is. All I want is to create a duplicate object and manipulate the new object without affecting the original object's data.
Let's say I have a class TicTacToe and I've created 2 objects, game1 and testField
TicTacToe game1 = new TicTacToe();
TicTacToe testField = new TicTacToe();
The class has multiple attributes, but here's the one being affected in this case
String[] gameField[9];
All I want to do is go into a for loop with the newly initialized object, set its 'gameField' to the 'gameField' of object "game1". Don't mind all the nonsense going on... Also, after each loop, it resets back to the "game1" object
TicTacToe testField = new TicTacToe();
for (int i = 0; i < 9; i++)
{
testField.gameField = game1.gameField;
q = i+1;
if (testField.gameField[i].equals("" + q))
{
if (testField.humanStart) testField.gameField[i] = "O";
else testField.gameField[i] = "X";
game1.printField();
testField.printField();
if (testField.checkWin() == 2)
{
bestMove = "" + q;
break;
}
}
}
The problem here is that BOTH objects are affected, even though it is supposed to be resetting.
Sorry if I wasn't clear enough.
Thank you for the help.
The problem is with the line testField.gameField = game1.gameField;
I think what you want to do is:
System.arraycopy( testField.gameField, 0, game1.gameField, 0, testField.gameField.length );
Alternatively, you could do:
testField.gameField = game1.gameField.clone();
This is referred to as defensive copying. You have more details - here
Also, you can create an object, but instead of merely assigning the object (in which case you assign the location of the original object to the new one), you can also create all individual elements and copy the values. This will create a new object and hence, not modify the original.

Check if array is NULL at a Specific Index returns NullPointerException

I am trying to add an object of type Car to an Array of cars, I do not have a specific index within the array that I want the car to go into, I just want to add the car to the first empty and available index that doesn't have a car object already in there. Here is my code:
protected static final int MaxCars = 5;
protected Car[] cars = new Car[MaxCars];
public void addCar(Car c)
{
for(int i = 0; i < MaxCars; i++)
{
if (cars[i] == null)
{
cars[i] = c;
break;
}
}
incrementNumInTeam();
}
On the if statement inside the for loop I am getting the a NullPointerException .. how can I overcome this?
Your variable cars is likely null at the time the if block is called. Your error is present but likely elsewhere in your code. Check to be sure that you're not shadowing the cars variable and that the variable being initialized is the same one being read.

ArrayItem equals atleast one term in another array

I want to check to see if two arrays share at least one term in common for my program.
I'm not quite sure what the code is to compare two arrays, but here is what I have so far;
if ((modWikiKeyArray).equals(inputArray[0]))
{
StringBuilder hyperlinkBuilder = new StringBuilder();
for(int i = 0; i < modWikiKeyArray.length; i++)
{
hyperlinkBuilder.append(modWikiKeyArray[i]);
}
}
How would I compare the array modWikiKeyArray to inputArray just to check and see if inputArray[0] is equal to any term inside of modWikiKeyArray?
Arrays.asList lets you build a list backed by an arbitrary array and use convenient Java Collections Framework features like the contains method:
Arrays.asList(oneArray).contains(elementFromAnotherArray)
If you want to see if the arrays have at least one element in common, you could build a HashSet out of one and loop over the other to try to find a common element:
boolean arraysIntersect(Object[] array1, Object[] array2) {
Set array1AsSet = HashSet(Arrays.asList(array1));
for (Object o : array2) {
if (array1AsSet.contains(o)) {
return true;
}
}
return false;
}
You can do the following
for(int i=0;i<modWikiKeyArray.length;i++) {
if(modWikiKeyArray[i].equals(inputArray[0])) {
System.out.println("Match found");
}
}
Note you need to override the equals() method of whatever array you are creating(Class of which array you are creating) .
Going by your code snippet, it looks like you need to check the presence of inputArray[0] only, in which case the following is sufficient:
boolean exists = java.util.Arrays.asList(modWikiKeyArray).contains(inputArray[0]);
Alternatively, you might also want to use ArrayUtils from Apache commons-lang:
boolean exists = ArrayUtils.contains(modWikiKeyArray, inputArray[0]);
However, if I read the text of your question, it seems you want to find if modWikiKeyArray contains at least one item from inputArray. For this you may also use retainAll from the Collections API to perform a list intersecion and see if the intersection list is non-empty.
However, the most primitive is still Aniket's method. However, I will modify it to reduce unnecessary operations:
int i = modWikiKeyArray.length - 1;
MyObject inputElement = inputArray[0];
boolean found = false;
for(; i != 0; i--) {
if(modWikiKeyArray[i].equals(inputElement)) {
found = true;
break;
}
}

Remove item from ArrayList issue

I'm writing a class that have a method of removing an object from other class. But it just worked inproperly, the output is not correct. Please help me through, and is there any better solution for this, I think my solution is quite cumbersome. Here is my code:
public List<Task> getTaskDue(){
List<Task> temp = this.taskCollection;
for (int unit = 0; unit < this.unitCollection.size(); unit++){
for (int j = 0; j < this.unitCollection.get(unit).getAssessmentCollection().size(); j++){
for (int i = 0; i < temp.size(); i++){
if (temp.get(i).getDueDate().compareTo(this.unitCollection.get(unit).getAssessmentCollection().get(j).getDueDate()) > 0)
temp.remove(i);
}
}
}
return temp;
}
Updated: I have Diary class that has list of Task class and Assessment class that hold due date attribute. I want to create a method that return a new list which have a list of over due task by comparing the task from diary class with the due date attribute from assessment class. The program compile successfully but the result is not correct if I want to test the list return no task item since no task is over due.
It seems like "removing" elements from the list isn't your ultimate problem.
You said you want your method to return a new list that contains elements from taskCollection based on some criteria. At the same time, I don't think you want to destroy or change taskCollection in any way.
So instead of creating temp as a reference to taskCollection, have it be a new ArrayList<Task>() instead. Then add tasks to temp (the new list) that you want to ultimately return from your method.
I am going to leave my adivce at that, because your code sample, in isolation, has a lot of unknowns that prohibit me from making any educated guesses on what you really need it to do.
Also, there are too many for loops! (I'm mostly kidding, but seriously...)
With more information from the comments below, I've modified your code to implement what I am suggesting. In order to add the items to temp (instead of remove them) I had to change your if statement from > 0 to <= 0. Also, instead of iterating over taskCollection in the inner-most loop, you should get tha tasks from the current assessment and iterate over those.
public List<Task> getTaskDue(){
List<Task> temp = new ArrayList<Task>();
for(int u = 0; u < unitCollection.size(); u++){
Unit unit = unitCollection.get(u);
for (int a = 0; a < unit.getAssessmentCollection().size(); a++){
AssessmentItem assessment = unit.getAssessmentCollection().get(a);
for (int t = 0; t < assessment.getTasks().size(); t++){
Task task = assessment.getTasks().get(t);
if (task.getDueDate().compareTo(assessment.getDueDate()) <= 0){
temp.add(task);
}
}
}
}
return temp;
}
If you need to alter a list as you're iterating through it, use a ListIterator. Call listIterator() on your list to create one, then see relevant methods on ListIterator.
You are removing an object from an index but index in iteration is not altered. Due to the reason you would be skipping an element in the list. Perhaps that is the reason why your results are not correct.
Change:
if ( temp.get( i ).getDueDate().compareTo( this.unitCollection.get( unit )
.getAssessmentCollection().get( j ).getDueDate() ) > 0 )
temp.remove(i);
to:
if ( temp.get( i ).getDueDate().compareTo( this.unitCollection.get( unit )
.getAssessmentCollection().get( j ).getDueDate() ) > 0 )
{
temp.remove(i);
i--;
}
PS: Better always practice using flower braces irrespective of number of statements under the condition or loop.

Java BucketSort

I'm sure you probably get this a lot from CompSci students, I tried searching but mine looked a lot different from anything else I could find. Anyway, here is my class, it is supposed to sort an array of integers (then in the future be modified to sort objects, but ints will do for now).
My goal is to make an arrayList which is basically a row of buckets. then each bucket is a linked list. I feel like I'm on the right track, but the compiler doesn't like my last line of code, so I've run out of ideas.
here's an update. this is what I have now, but I still don't think it'll work
public void sorter(){
int highest_int = 0;
for(int i=0; i<entries.length; i++){
if (highest_int < entries[i])
highest_int = entries[i];
}
ArrayList<LinkedList<Integer>> row = new ArrayList<LinkedList<Integer>>();
LinkedList<Integer> column = new LinkedList<Integer>();
while (highest_int>0){
row.add(column);
highest_int--;
}
for(int i=0; i<entries.length; i++){
int j = entries[i];
column.add(0, j);
row.set(j, column);
}
}
The compiler "doesn't like" your code because the add() method of LinkedList doesn't return anything (has void return type). Therefore it cannot be used as an argument to the set() method. Basically, add() modified the object that it is called on, but doesn't return that object as a value.
The simplest change I can suggest that I think will make your code compile would be:
for(int i=0; i<entries.length; i++){
int j = entries[i];
column.add(0, j);
row.set(j, column);
}
Beyond that, it's not clear to me what you are actually trying to accomplish here. I don't see anything that looks like a sort at all.
The compile problem is that column.add() returns void.
A bigger problem is that the same LinkedList is used for each bucket. You need to create a new LinkedList in each iteration of one of the for loops.

Categories

Resources