2009-12-04 5 views
0

Сегодня у меня возникла странная проблема: у меня был метод, в котором в качестве аргументов были взяты два объекта Date. Вызывающий метод передал ссылку на тот же объект, что и оба из них (рассматриваемый метод был EqualsBuilder.append). Первый параметр получил отлично, а второй - нет. Это был новый объект Date, который отличался от первого в том смысле, что все поля, за исключением года и дня года, были установлены в 0. Обратите внимание, что у меня не было никакого кода, который бы скопировал объект ... Это ошибка в JVM?Почему JVM создает копию объекта при передаче его методу?

Код был довольно напряженным, и я заметил только это, потому что мой юнит-тест потерпел неудачу при сравнении того, что должно было быть тем же самым объектом (я инициализировал его каким-то случайным длинным).

Edit:

  • Я не верил, что сам ...
  • я не предполагал ошибку в JVM, я потратил буквально 4 часа, глядя на этот код и отладку.
  • Я посмотрел в отладчике, чтобы убедиться, что они являются одним и тем же объектом (также будет проверяться с помощью метода == в методе вызова в понедельник).
  • Я использую 1.6.0_17 для Windows XP
  • Я не могу опубликовать реальный код прямо сейчас, сделаем это в понедельник.

Edit 2:

  • После перезапуска Eclipse, я не могу воспроизвести ошибку
  • У меня есть 7 глаз свидетелей, которые могут свидетельствовать, что это случилось :)
  • на этих свидетелей сказал что на предыдущем концерте они столкнулись с чем-то до такой степени и что они столкнулись с этой ошибкой (или странным поведением) раз в 3 года
  • , следовательно, я полагаю, что мои шансы на репродуцирование г ситуация довольно тонкая (я действительно хотел, чтобы я взял скриншоты)

Edit 3:

  • Вот код для данного класса:

    импорта java.util .Дата; import java.util.List;

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(); 
} 

}

  • И тест блок, который не удалось: импорт java.util.Arrays; import java.util.Date; импорт java.util.Список;

импорт статический org.junit.Assert. *; import 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 есть ошибка (хотя это часть программного обеспечения, а программное обеспечение без ошибок).

Прямо сейчас я проверил код с конструктором, который вызвал ошибки, в первую очередь, возможно, мне посчастливится столкнуться с этим снова. Спасибо за отзывы.

+8

Опубликовать код будет бесконечно ясным, чем его описание. –

+6

Я этому не верю. Я согласен с @Jonathan Feinberg. Давайте посмотрим на код. – bmargulies

+1

I третий это. Посмотрим на код. –

ответ

3

Ваше утверждение о том, что JVM копирует объект, когда оно передается как аргумент метода, является необычным и (для меня) невероятным без каких-либо конкретных доказательств. Укажите исходный код вызываемых/вызываемых методов, которые, по вашему мнению, демонстрируют это поведение, а также подробную информацию о вашей версии JVM и платформе оборудования/ОС.

"Extraordinary claims require extraordinary proof".


После перезапуска Eclipse, я не могу воспроизвести ошибку

Это указывает на это будучи "Затмение странность" проблема. Я ожидаю, что странность Eclipse означала, что вы запускали код, который не соответствовал исходному коду, на который вы смотрели. Но мы никогда не узнаем наверняка ...

0

Этот код:

public void testDates() { 
    Date d = new Date(); 

    runTest(d, d); 
} 

private void runTest(Date a, Date b) { 
    System.out.println(a +" " +b); 
} 

напечатан этот результат для меня:

Fri Dec 04 22:14:28 GMT 2009 Fri Dec 04 22:14:28 GMT 2009 

это вписывается в ситуацию вы описываете? (Очевидно, что результата нет). Источник EqualsBuilder не похож на что-то необычное.

+0

это ужасно делает. и, конечно, результата нет :( –

1

Если объекты разные, они не могут быть одинаковыми в первую очередь. Мое подозрение в том, что вы ДУМАЕТЕ, что у вас есть две ссылки на один и тот же объект, но у вас есть два объекта. Как вы определили, что у вас был только один объект?

2

В объектах Java никогда не копируются при передаче в методы. В Java все переменные передаются по значению, а в случае объектов ссылка на объект передается по значению. Существует никогда копирование сделано.

+0

никогда не говори никогда ... Я тоже не мог поверить. –

+0

@ Бартош: в этом случае это нормально нормально говорить никогда. Вы ошибаетесь :) – Fredrik

1

Я собираюсь предположить, что java.sql.Date замешан в этом как-то (на основании заявления «все поля за исключением года и дня года были установлены в 0»).

Смежные вопросы