Reputation: 18564
I encountered a strange problem today: i had a method that took two Date objects as arguments. The calling method passed reference to the very same object as both of them (the method in question was EqualsBuilder.append). The first parameter got passed fine, but the second one not. It was a new Date object that was different from the first one in the sense that all the fields except for year month and day were set to 0. Note that I didn't have any code that would copy the object... Is that a bug in the JVM?
The code was pretty straighforward and I only noticed that because my unit test failed on comparison of what supposed to be the very same object (i initialized it with some random long).
Edit:
Edit 2:
Edit 3:
Here's the code for the class in question:
import java.util.Date; import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder;
public class Foo {
private final long roadId;
private final Date creationDate;
private final Date editDate;
private final List<String> vehicleTypes;
private final boolean continuous;
public Foo(final long roadId, final Date creationDate, final Date editDate, final List<String> vehicleTypes, final boolean continuous) {
super();
this.roadId = roadId;
this.creationDate = creationDate;
this.editDate = editDate;
this.vehicleTypes = vehicleTypes;
this.continuous = continuous;
}
public long getRoadId() {
return roadId;
}
public Date getCreationDate() {
return creationDate;
}
public Date getEditDate() {
return editDate;
}
public List<String> getVehicleTypes() {
return vehicleTypes;
}
public boolean isContinuous() {
return this.continuous;
}
@Override
public int hashCode() {
final HashCodeBuilder builder = new HashCodeBuilder();
builder.append(this.roadId);
builder.append(this.creationDate);
builder.append(this.editDate);
builder.append(this.vehicleTypes);
builder.append(this.continuous);
return builder.toHashCode();
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Foo)) {
return false;
}
final Foo other = (Foo)obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(this.roadId, other.roadId);
builder.append(this.creationDate, other.creationDate);
builder.append(this.editDate, other.editDate);
builder.append(this.vehicleTypes, other.vehicleTypes);
builder.append(this.continuous, other.continuous);
return builder.isEquals();
}
}
import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test;
public class FooTest {
private static final boolean CONTINUOUS = true;
private static final Date CREATION_DATE = new Date(12345678901L);
private static final Date EDIT_DATE = new Date(987654321654321L);
private static final long ROAD_ID = 101;
private static final List<String> VEHICLE_TYPES = Arrays.<String> asList("TEST");
private Foo nonEmpty;
private Foo otherNonEmpty;
@Before
public void setUp() {
this.nonEmpty = new Foo(FooTest.ROAD_ID, FooTest.CREATION_DATE,
FooTest.EDIT_DATE, FooTest.VEHICLE_TYPES, true);
this.otherNonEmpty = new Foo(FooTest.ROAD_ID, FooTest.CREATION_DATE,
FooTest.EDIT_DATE, FooTest.VEHICLE_TYPES, FooTest.CONTINUOUS);
}
@Test
public void testEquals() {
assertTrue(this.nonEmpty.equals(this.otherNonEmpty));
}
}
Now, if I changed this:
private static final Date CREATION_DATE = new Date(12345678901L);
private static final Date EDIT_DATE = new Date(987654321654321L);
to this:
private static final Date CREATION_DATE = new Date(109,1,11);
private static final Date EDIT_DATE = new Date(110,3,13);
it worked fine.
I don't think that the code is wrong, especially that after restarting the JVM all the tests passed. At the same time I know that it's highly unlikely that there is a bug in the JVM (although it is a piece of software and the no software is bug-free).
Right now I have checked in the code with the constructor that caused errors in the first place, perhaps I will be lucky enough to encounter that again. Thanks for feedback.
Upvotes: 0
Views: 447
Reputation: 719229
Your assertion that a JVM is copying an object when it is passed as a method argument is extraordinary, and (to me) unbelievable without some concrete evidence. Please provide the source code of the calling / called methods that you believe exhibits this behavior, and details of your JVM version and hardware / OS platform.
"Extraordinary claims require extraordinary proof".
After restarting eclipse, I cannot reproduce the bug
That points to this being an "Eclipse weirdness" problem. I expect that the Eclipse weirdness meant that you were running code that didn't match the source code you were looking at. But we will never know for sure ...
Upvotes: 3
Reputation: 9928
I'm going to suggest that java.sql.Date
is mixed up in this somehow (based on the statement, "all the fields except for year month and day were set to 0").
Upvotes: 1
Reputation: 6027
In Java objects are never copied when passed into methods. In Java all variables are passed by value, and in the case of objects the reference to the object is passed in by value. There is never copying done.
Upvotes: 2
Reputation: 75406
If the objects are different they cannot be the same in the first place. My suspicion is that you THINK you have two references to the same object, but you have two objects. How did you determine you only had one object?
Upvotes: 1
Reputation: 19414
This code:
public void testDates() {
Date d = new Date();
runTest(d, d);
}
private void runTest(Date a, Date b) {
System.out.println(a +" " +b);
}
printed this result for me:
Fri Dec 04 22:14:28 GMT 2009 Fri Dec 04 22:14:28 GMT 2009
Does that fit the situation you're describing? (Obviously the result doesn't). The source of EqualsBuilder doesn't look like there's anything unusual about it.
Upvotes: 0