Как получить «объектную ссылку» объекта в java, когда toString () и hashCode () были переопределены?

106

Я хотел бы напечатать «ссылку на объект» объекта в Java для целей отладки. Т.е. убедиться, что объект одинаковый (или другой) в зависимости от ситуации.

Проблема в том, что рассматриваемый класс наследуется от другого класса, который переопределяет как toString (), так и hashCode (), которые обычно дают мне идентификатор.

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

Николай
источник
1
в зависимости от того, можете ли вы вообще это сделать ... == - это путь ... но я понятия не имею, как структурирован рассматриваемый код. Опять же, hashCode, вероятно, подходит для того, что вы делаете, но он может сломаться в зависимости от того, как реализована библиотека.
TofuBeer
Это действительно хороший вопрос.
Чжан Сян

Ответы:

108

Что именно вы планируете с ним делать (от того, что вы хотите сделать, зависит, что вам нужно будет позвонить).

hashCode, как определено в JavaDocs, говорит:

Насколько это разумно практично, метод hashCode, определенный классом Object, действительно возвращает отдельные целые числа для отдельных объектов. (Обычно это реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется для языка программирования Java ™.)

Поэтому, если вы используете, hashCode()чтобы узнать, является ли это уникальным объектом в памяти, это не лучший способ сделать это.

System.identityHashCode делает следующее:

Возвращает тот же хэш-код для данного объекта, который был бы возвращен методом hashCode () по умолчанию, независимо от того, переопределяет ли класс данного объекта hashCode (). Хэш-код для нулевой ссылки равен нулю.

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

Тофу пиво
источник
6
Я не действую на значение в коде. Как пр. Мой вопрос редактируется, я использую его только для отладки в определенной ситуации. Вот почему я считаю свой ответ разумным, но даю вам +1 за содержательный ответ.
Николай
1
Скорее всего, он всегда будет делать то, что вы хотите, но на некоторых виртуальных машинах он может сломаться.
TofuBeer
Он сломается (т.е. identityHashCode не обязательно будет уникальным) на любой разумной виртуальной машине. identityHashCode - это не идентификатор
Том Хотин - tackline
Как уже упоминалось, нет гарантии, что хэш-код основан на адресе. Я видел несколько объектов с одинаковым идентификатором в виртуальной машине IBM внутри WAS.
Робин,
«Обычно это реализуется путем преобразования внутреннего адреса объекта в целое число» не по гарантии, а по умолчанию от Sun. Такие вещи, как s = "Hello" и t = "Hello", вероятно, приведут к тому, что s и t будут иметь один и тот же identityHashCode, поскольку они действительно являются одним и тем же объектом.
TofuBeer
50

Вот как я это решил:

Integer.toHexString(System.identityHashCode(object));
Николай
источник
5
На самом деле это неверно, поскольку несколько объектов могут возвращать один и тот же identityHashCode.
Робин,
2
Разве не правда, что два объекта (ссылки) с одним и тем же хешем идентичности являются одним и тем же объектом? вот чего хочет OP
basszero
3
Нет, это неправда. Это очень вероятно, но не гарантируется, поскольку спецификация НЕ определяет алгоритм.
Робин
8

Двойное равенство ==всегда будет проверять на основе идентичности объекта, независимо от реализации объектами hashCode или equals. Конечно - убедитесь, что ссылки на объекты, которые вы сравниваете, соответствуют volatile(в 1.5+ JVM).

Если вам действительно нужен исходный результат Object toString (хотя это не лучшее решение для вашего примера использования), в библиотеке Commons Lang есть метод ObjectUtils.identityToString (Object), который будет делать то, что вы хотите. Из JavaDoc:

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

Получает toString, который был бы создан Object, если бы класс не переопределил сам toString. 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 () может не возвращать адрес, и, как уже упоминалось, возможно несколько объектов с одним и тем же hashCode. Единственный способ добиться того, что вы хотите, - это фактически переопределить метод hashCode () для рассматриваемых объектов и гарантировать, что все они предоставляют уникальные значения. Возможно ли это в вашей ситуации - другой вопрос.

Для записи я испытал несколько объектов с одним и тем же хэш-кодом по умолчанию в виртуальной машине IBM, работающей на сервере 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 и запросить это свойство. Будет безопасно внутри одной виртуальной машины (при условии, что нет игры с загрузчиками классов, чтобы обойти статику).

Майкл Майерс
источник
Я бы, вероятно, использовал AtomicInteger в этом сценарии - он имеет более высокую пропускную способность, потому что синхронизация не требуется, и он использует собственные операции атомной памяти, предоставляемыеsun.misc.Unsafe
RAnders00
1

мы можем просто скопировать код из строки класса объекта, чтобы получить ссылку на строку

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)));
  }
}
Никхил Джайтак
источник