Как получить «объектную ссылку» объекта в 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)));
  }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.