Як отримати "посилання на об'єкт" об'єкта в Java, коли параметри toString () і hashCode () були замінені?


106

Я хотів би надрукувати "посилання на об'єкт" об'єкта в Java для цілей налагодження. Тобто переконатися, що об’єкт однаковий (або різний) залежно від ситуації.

Проблема полягає в тому, що відповідний клас успадковується від іншого класу, який переосмислив іString (), і hashCode (), які зазвичай дають мені ідентифікатор.

Приклад ситуації: Запуск багатопотокової програми, де я (під час розробки) хочу перевірити, чи всі потоки використовують один і той же примірник ресурсного об’єкта чи ні.


1
залежно від того, чи можна взагалі це зробити ... == це шлях ... але я не маю уявлення про те, як зачіпається код, про який йде мова. Знову ж, hashCode, ймовірно, добре для того, що ви робите, але він може зламатися залежно від того, як бібліотека реалізована.
TofuBeer

Це справді гарне запитання.
Чжан Сян

Відповіді:


108

Що саме ви плануєте робити з цим (те, що ви хочете зробити, має значення для того, що вам потрібно буде зателефонувати).

hashCode, як визначено в JavaDocs, говорить:

Наскільки це практично практично, метод хеш-коду, визначений класом Object, повертає окремі цілі числа для різних об'єктів. (Зазвичай це реалізується шляхом перетворення внутрішньої адреси об'єкта в ціле число, але ця техніка реалізації не потрібна мові програмування Java ™.)

Тож якщо ви використовуєте, hashCode()щоб дізнатися, чи це унікальний об'єкт у пам'яті, це не гарний спосіб зробити це.

System.identityHashCode робить наступне:

Повертає той самий хеш-код для даного об'єкта, який буде повернутий методом за замовчуванням hashCode (), незалежно від того, клас класу даного об'єкта перекриває хеш-код (). Хеш-код для нульової посилання дорівнює нулю.

Що для того, що ви робите, звучить як те, що ви хочете ... але те, що ви хочете зробити, може бути не безпечним залежно від того, як бібліотека реалізована.


6
Я не дію на значення в коді. Як пр. моє запитання редагувати, я використовую його лише для налагодження певної ситуації. Тому я вважаю, що моя відповідь є розумною, але я даю вам +1 за глибоку відповідь.
Миколай

1
шанси на те, що він завжди буде робити те, що ви хочете - але це може зламатися на деяких віртуальних машинах.
TofuBeer

Він порушиться (тобтодентифікаціяHashCode не обов'язково буде унікальною) на будь-якому розумному VM.
identHashCode

Як вже було сказано, немає гарантії того, що хеш-код базується на адресі. Я бачив, що в IBM VM всередині WAS відбувається декілька об'єктів з однаковим ідентифікатором.
Робін

"Це зазвичай реалізується шляхом перетворення внутрішньої адреси об'єкта в ціле число" не гарантії, а реалізації за замовчуванням від Sun. Такі речі, як s = "Hello" і t = "Hello", ймовірно, призведе до того, що s і t мають таку ж ідентичністьHashCode, як вони насправді є одним і тим же об'єктом.
TofuBeer

50

Ось як я це вирішив:

Integer.toHexString(System.identityHashCode(object));

5
Це насправді не правильно, оскільки кілька об'єктів можуть повернути один і той же ідентифікаційний кодHashCode.
Робін

2
Чи не правда, що два об'єкти (посилання) з однаковим хешем ідентичності є одним і тим же об'єктом? ось чого хоче ОП
basszero

3
Ні, це неправда. Це дуже ймовірно, але не гарантується, оскільки специфіка НЕ ​​визначає алгоритм.
Робін

8

Подвійні рівні ==завжди перевірятимуться на основі ідентичності об'єкта, незалежно від реалізації об'єктами hashCode або рівних. Звичайно - переконайтеся, що посилання на об'єкти, з якими ви порівнюєте, volatile(у 1.5+ JVM).

Якщо ви дійсно повинні мати оригінальний результат ObS toString (хоча це не найкраще рішення для вашого прикладу використання), у бібліотеці Commons Lang є метод ObjectUtils.identityToString (Object), який буде робити те, що ви хочете. З JavaDoc:

public static java.lang.String identityToString(java.lang.Object object)

Отримує toString, який був би створений Object, якби клас не переосмислював себе theString. null поверне null.

 ObjectUtils.identityToString(null)         = null
 ObjectUtils.identityToString("")           = "java.lang.String@1e23"
 ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"

1
Якщо ви використовуєте Java 7, то вам слід розглянути можливість використання java.util.Objects
noahlz

5

Ви не можете безпечно робити те, що ви хочете, оскільки хеш-код () за замовчуванням може не повернути адресу, і, як було зазначено, можливі кілька об'єктів з одним і тим же хеш-кодом. Єдиний спосіб досягти того, що ви хочете, - це фактично замінити метод hashCode () для відповідних об'єктів і гарантувати, що всі вони надають унікальні значення. Чи це можливо у вашій ситуації - інше питання.

Для запису я зазнав декількох об'єктів з однаковим хеш-кодом за замовчуванням у IBM VM, що працює на сервері WAS. У нас був дефект, коли об’єкти, поміщені у віддалений кеш, через це будуть перезаписані. Це було відкриття очей для мене в той момент, оскільки я припустив, що хеш-код за замовчуванням був також адресою пам'яті об'єктів.


2

Додайте унікальний ідентифікатор для всіх своїх примірників, тобто

public interface Idable {
  int id();
}

public class IdGenerator {
  private static int id = 0;
  public static synchronized int generate() { return id++; }
}

public abstract class AbstractSomething implements Idable {
  private int id;
  public AbstractSomething () {
    this.id = IdGenerator.generate();
  }
  public int id() { return id; }
}

Розгорнути з AbstractSomething і запитати цю властивість. Буде безпечно всередині одного vm (якщо не грати з навантажувачами, щоб обходити статику).


Я б, мабуть, використовував AtomicInteger в цьому сценарії - він має більшу пропускну здатність, оскільки синхронізація не потрібна, і він використовує вбудовані операції з атомною пам'яттю, передбаченіsun.misc.Unsafe
RAnders00

1

ми можемо просто скопіювати код з tostring класу об'єктів, щоб отримати посилання на рядок

class Test
{
  public static void main(String args[])
  {
    String a="nikhil";     // it stores in String constant pool
    String s=new String("nikhil");    //with new stores in heap
    System.out.println(Integer.toHexString(System.identityHashCode(a)));
    System.out.println(Integer.toHexString(System.identityHashCode(s)));
  }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.