Сегодня я столкнулся со странной проблемой: у меня был метод, который использовал два объекта Date в качестве аргументов. Вызывающий метод передал ссылку на тот же объект, что и они оба (рассматриваемый метод был EqualsBuilder.append). Первый параметр прошел нормально, а второй нет. Это был новый объект Date, который отличался от первого в том смысле, что все поля, кроме года и месяца и дня, были установлены на 0. Обратите внимание, что у меня не было никакого кода, который бы копировал объект ... ошибка в JVM?
Код был довольно простым, и я заметил это только потому, что мой модульный тест не удался при сравнении того, что должно было быть тем же объектом (я инициализировал его с некоторой случайной длинной).
Редактировать :
- Я сам в это не верил ...
- Я не предполагал ошибки в JVM, я потратил буквально 4 часа, уставившись на этот код и отлаживая его.
- Я посмотрел в отладчике, чтобы убедиться, что это один и тот же объект (в понедельник также будет проверено с == в вызывающем методе).
- Я использую 1.6.0_17 в Windows XP
- Я не могу опубликовать действительный код прямо сейчас, я сделаю это в понедельник.
Редактировать 2 :
- После перезапуска затмения я не могу воспроизвести ошибку
- У меня есть 7 очевидцев, которые могут засвидетельствовать, что это произошло:)
- один из этих свидетелей сказал, что на предыдущем концерте они сталкивались с чем-то в такой степени и что они сталкивались с этой ошибкой (или странным поведением) один раз в 3 года
- следовательно, я предполагаю, что мои шансы воспроизвести ситуацию довольно малы (я действительно хотел бы, чтобы я делал снимки экрана)
Редактировать 3 :
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
публичный класс 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 java.util.Arrays;
импорт java.util.Date;
import java.util.List;
import static org.junit.Assert. *;
импорт org.junit.Before;
import org.junit.Test;
публичный класс 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));
}
}
Теперь, если я изменил это:
private static final Date CREATION_DATE = new Date(12345678901L);
private static final Date EDIT_DATE = new Date(987654321654321L);
на это:
private static final Date CREATION_DATE = new Date(109,1,11);
private static final Date EDIT_DATE = new Date(110,3,13);
все работало нормально.
Я не думаю, что код неправильный, тем более что после перезапуска JVM все тесты пройдены. В то же время я знаю, что очень маловероятно, что в JVM есть ошибка (хотя это часть программного обеспечения, и ни одно программное обеспечение не содержит ошибок).
Прямо сейчас я проверил код с конструктором, который сначала вызвал ошибки, возможно, мне повезет встретить это снова. Спасибо за отзыв.