views:

107

answers:

5

hi there!

i'm writing some stuff in java and i ran into some problems lately. cut short, i need to compare an object i created to another instance of this very class i instantiazed before with different data.

looks like this:

a newA = null;
a oldA = null;

while(someBreakCondition) {
    newA = new a();

    newA.x = getSomeValue();

    // now i want to compare the two objects
    if(oldA != null) {
        if(newA.time != oldA.time) {
            // ...
        }
    }

    // now my newA gets to be my oldA, since in the next iteration, a new newA is created
    oldA = newA;
}

with a class a:

class a {
    public long time;
    public int x;

    public a() {
        time = System.currentTimeMillis;
    }
}

the problem is, that i end up finding out that the values from newA are always equal to those from oldA. so i guess sth went wrong with passing the references of the objects in the last line of the loop... i thought java always passes references of objects unless an explicit copy() is called?

if this does matter: this code is running on android - don't know if the dalvik vm messes aroung with this...

+7  A: 

I'm thinking you probably do have two different objects, but they both have the same value for time. Current millis doesn't quite have the precision to distinguish between two objects constructed in rapid succession, unless if your inner loop is long running. Even a Mhz processor will have iterations measured in microseconds, not milliseconds.

wds
+1 note: the inner loop will only be run if both times are different, so, at least during the first millisecond, there is no impact if the inner loop is long running.
Carlos Heuberger
Ah right, good catch. So the code is basically constructing at least a couple 1000 objects before the milliseconds tick over.
wds
+4  A: 

There is a chance, that two a objects are created within the same millisecond, so there 'time' fields are equal.

I'm not sure about you comparision requirements, but maybe you should overwrite equals:

public class A {
  private long time;
  private int x;

  public A() {
    time = System.currentTimeInMillis();
  }

  public void setX(int x) {
    this.x = x;
  }

  public int getX() {
    return x;
  }


  public boolean equals(Object other) {
    if (!(other instanceof A)) return false;

    // two A instances are equal if they are created 
    // within the same millisecond
    return ((A) other).time == time);
  }
}

then just do a

if (!(newA.equals(oldA)) {
  // ...
}

For future coding - please name classes so that they start with an upper case letter (coding conventions)

Andreas_D
A: 

In the last line of your loop you write oldA=newA this makes oldA and newA share the same reference. So, when you change the value of newA with newA=new a(), the value of oldA changes too (so you will have oldA.x==newA.x).

Edit: I've made some tests and i discovered that what I said was totally wrong, sorry about that. However, the code given by xenonite works fine. The condition newA.time != oldA.time is satisfied.

Aymen
No! No! No! this is absolutly incorrect! `oldA` stores a reference to an instance of `a` and this will never change, when you assign a new instance of `a` to `newA`.
Andreas_D
Andreas is right. You can think of `oldA` and `newA` as two pointers. `oldA` = `newA` makes them both point to the same object. When you execute `newA = new A()` you make `newA` point to a different (a new) object. This has no influence whatsoever on `oldA`.
wds
-1 for being incorrect. If `oldA=newA;`, yes they will point to the same object, but `newA= new a();` **does not** alter the object that `oldA` refers to. All it does is create a new instance of `a` and store the reference in `newA`, so that `oldA` and `newA` refer to different objects
chrisbunney
(removed my downvote after your edit)
Andreas_D
+1  A: 

I don't know how to put code into comments so I'll add this as a response to Aymen's answer which is wrong :)

Try this and you'll see exactly what's going on :)

public class Test {
  private int value;
  public Test(){

  }

  public int getValue() {
    return value;
  }

  public void setValue(int value) {
    this.value = value;
  }


}

public class Main {

    public static void main(String[] args) {
      Test oldA = null;
      Test newA = null;


      newA = new Test();
      newA.setValue(1);

      oldA = newA;

      // both variables references the same object: output: 1 - 1
      System.out.println("newA: " + newA.getValue());
      System.out.println("oldA: " + oldA.getValue());

      newA = new Test();
      newA.setValue(2);

      // now we have different objects: output: 2 - 1
      System.out.println("newA: " + newA.getValue());
      System.out.println("oldA: " + oldA.getValue());

    }

}
Bogdan
+1  A: 

By "I end up with", do you mean "after I get out of the while loop"?

Because in that case, then the problem is simple: in the last loop iteration, oldA is overwritten with the last value of newA, while newA is never overwritten with a new instance of a.

So, when you get out of the while loop, newA and oldA are always equal - the consequence of the last attribution step of the last loop execution.

jhominal