0

I have an assignment I am working on where I have two classes.

Class A is called Points. It contains data for a 2D coordinate, and additional data associated to that specific point.

Class B is called Particles. It contains an array of objects of class A as well as some additional information.

I have a list of Particles. At initialization, all Particle objects contain an identical array of Points.

If I then change the value of the first position in the Points array in any Particle, I then see that all other Particles have mirrored this change. This is not the bahaviour I want. Instead, I want any changes in any Particle to be unique to that object.

public static class Particle{
    public double[][] current = new double[NC][2];
    public double[][] pBest = new double[NC][2];
    public double[][] vel = new double[NC][2];
    public Points[] points = new Points[array.length];
    public double pbestfitness = 0.0;
    public Particle(){
    }
    //standard get/set methods here

}
public static class Points{
    public int x;
    public int y;
    public double centroidx;
    public double centroidy;

    public Points(){
        this.x = -1;
        this.y = -1;
        this.centroidx = -1;
        this.centroidy = -1;
    }

    public int getx(){
        return x;
    }
    public void setx(int a){
        x = a;
    }
    public int gety(){
        return y;
    }
    public void sety(int a){
        y = a;
    }
    public double getcx(){
        return centroidx;
    }
    public void setcx(double a){
        centroidx = a;
    }
    public double getcy(){
        return centroidy;
    }
    public void setcy(double a){
        centroidy = a;
    }
}

initialization:

for(int i = 0; i < NP; i++){
        p = new Particle();
        initbest = new double[NC][2];
        points = new Points[array.length];
        points = array.clone();
        for(int j = 0; j < NC; j++){
            x = minx + r.nextInt(maxx - minx + 1);
            y = miny + r.nextInt(maxy - miny + 1);
            p.setCentroid(j, x, y);
            initbest[j][0] = x;
            initbest[j][1] = y;
        }
        p.setpBest(initbest);
        p.setVel(initV);
        p.points = points;
        particles.add(p);
    }

I thought that the issue was that I was copying each array of type A by address location rather than value, so I tried using System.arraycopy, and Arrays.copyOf() as well as array.clone, but none of them worked.

Here is code where I make a change to one object, but the change is mirrored in all objects:

particles.get(i).points[j].centroidx = particles.get(i).current[closest][0];
particles.get(i).points[j].centroidy = particles.get(i).current[closest][1];

The idea is basically I'm taking a set of point, adding a bunch of centroids, then finding which centroid is closest to each point and associating that point to that centroid. I run this with a set number of random starting positions, hence why I need to have a set number of copies of the starting positions represented by particles. I have ensured that the calculation for finding the closest centroid works using a testing data set of a low number of set points and centroids.

What happens after I complete an iteration of the first particle is that all the other particles are changed, when I have explicitly stated that the centroids of just the first particle is being changed. After the end of the first iteration of all particles is completed, all particles carry identical points arrays with centroids equivalent to the last copy that was changed. instead of unique points arrays with centroid data associated with that particle.

So the first particle will have a list of points with centroids that are not found to be a member of that particle. Instead, it holds the centroid data of the last particle of the previous iteration.

h_k
  • 1,674
  • 1
  • 24
  • 46

2 Answers2

2

All the Point objects with same index reference the same object. So when you change one of them, all the other objects with the same index in all the arrays will change as well. You must make sure that on initialization you make a depp copy of all the Point objects. A deep copy means that the information (in fields) is all the same, but they refer to different objects (You must make a deep copy of the fields too). Arrays.copyOf will not help you because it will create a shallow copy (The points at the same index will refer to the same object.) You need to implement the clone method on point that will create a deep copy of the point. Then during initialization, just call point.clone(). See What is the difference between a deep copy and a shallow copy?.

Community
  • 1
  • 1
rabz100
  • 751
  • 1
  • 5
  • 13
  • I believe I am using the clone method in the initialization code that I provided, where "arrays" is an array of type Point. points is a Points array, with length the same as "array". I then call "points = array.clone()". Is that not the correct way to do a deep copy? – h_k Dec 09 '13 at 03:52
  • 1
    The correct way is for you to implement the clone method in Points. Then when you initialize each array, you would need to copy the elements individually into the array and call array[i].clone() – rabz100 Dec 09 '13 at 04:12
  • Alright, so I've changed the code a little as follows. In initialization: for(int j = 0; j < array.length; j++){ points[i] = array[i].clone(); } in the Points[] class, I've implemented the following: @Override public Points clone() { try { return (Points) super.clone(); } catch (Exception e) { return null; } } To no success. Now I am getting a nullpointerexception. – h_k Dec 09 '13 at 04:22
  • 1
    You must implement cloneable interface in the points class. public static class Points implements Cloneable. – rabz100 Dec 09 '13 at 04:27
  • Yes I have the Cloneable interface included. If I have it just return super.clone(), I get the error "Unhandled exception type CloneNotSupportedException", so I wrap it in a try/catch. Then, in my initialization method, I get the error that I need to cast the array[i].clone() into type Points. So the code changes to points[i] = (Points) array[i].clone(). Upon execution, I get a nullpointer exception when I try to print out the first Particle's centroidx after I have set it to something different. – h_k Dec 09 '13 at 04:34
  • public Points clone() { try { return (Points) super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } One change: Changed the signature from public Object clone to public Points clone. This required me to cast the return from "return super.clone()" to "return (Points) super.clone(). I could then remove the cast from the initialization method. Still getting that nullpointerexception though. – h_k Dec 09 '13 at 04:52
  • 1
    if it's null does that mean it's printing out the exception caught by clone. If so what is it? – rabz100 Dec 09 '13 at 05:02
  • I think I have gotten the rest of it figured out and printing the correct results. Thank you for all the help! I will mark your answer as correct, I just needed to tinker with it a little bit. – h_k Dec 09 '13 at 05:27
1

I have a couple of suggestions.

First, when you describe a problem for which you provide code, refer to the variables/arrays/whatever with the names they have in the code. I don't know what you mean by A and B, and don't intend to dig through the code enough to guess, only to be wrong.

Second, if changing the data in one place automatically shows up in the other, then you almost certainly have a reference to the same object in the two places. If you do this:

A a = new A();
B b = new B();
b.setA(a);
array1[0] = a;
array2[0] = b;

then a change to a will be reflected in the object in both array1 and array2.

To prevent that, you can create an object of type A that is a copy of a, and put THAT into b before putting b into array2. Look up information on the Object.clone() method.

arcy
  • 12,845
  • 12
  • 58
  • 103
  • Thank you for the suggestions, I've edited my original question. As for your solution, is my error that I am using the clone() method incorrectly? I've used it in my initialization block of code. I've also used System.arrayCopy() and Arrays.copyOf() and they have both lead to the same results. – h_k Dec 09 '13 at 03:59