Как получить «ссылку на объект» объекта в Java, если toString() и hashCode() переопределены?
Вопрос
Я хотел бы напечатать «ссылку на объект» объекта в Java для целей отладки.Т.е.чтобы убедиться, что объект одинаков (или различен) в зависимости от ситуации.
Проблема в том, что рассматриваемый класс наследуется от другого класса, который переопределил как toString(), так и hashCode(), которые обычно дают мне идентификатор.
Пример ситуации:Запуск многопоточного приложения, в котором я (во время разработки) хочу проверить, используют ли все потоки один и тот же экземпляр объекта ресурса или нет.
Решение
Что именно вы планируете с ним делать (то, что вы хотите сделать, имеет значение от того, что вам нужно будет вызвать).
hashCode
, как определено в JavaDocs, говорит:
Насколько это практически возможно, метод hashCode, определенный классом Object, возвращает разные целые числа для разных объектов.(Обычно это реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется языком программирования Java™.)
Итак, если вы используете hashCode()
чтобы выяснить, является ли этот объект уникальным в памяти, это не лучший способ сделать это.
System.identityHashCode
делает следующее:
Возвращает тот же хэш-код для данного объекта, который был бы возвращен методом hashCode() по умолчанию, независимо от того, переопределяет ли класс данного объекта hashCode().Хэш-код для нулевой ссылки равен нулю.
Что, учитывая то, что вы делаете, звучит как то, что вы хотите...но то, что вы хотите сделать, может быть небезопасно в зависимости от того, как реализована библиотека.
Другие советы
Вот как я это решил:
Integer.toHexString(System.identityHashCode(object));
Двойное равно ==
всегда будет проверять на основе идентичности объекта, независимо от реализации объектов hashCode или равных.Конечно, убедитесь, что ссылки на объекты, которые вы сравниваете, volatile
(в JVM 1,5+).
Если вам действительно необходим исходный результат Object toString (хотя это не лучшее решение для вашего примера использования), в библиотеке Commons Lang есть метод ObjectUtils.identityToString(Объект) это сделает то, что вы хотите.Из JavaDoc:
public static java.lang.String identityToString(java.lang.Object object)
Получает тостронг, который будет создан объектом, если бы класс не переопределяет самого ToString.NULL вернет NULL.
ObjectUtils.identityToString(null) = null
ObjectUtils.identityToString("") = "java.lang.String@1e23"
ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
Вы не можете безопасно делать то, что хотите, поскольку метод hashCode() по умолчанию может не возвращать адрес, и, как уже упоминалось, возможны несколько объектов с одним и тем же hashCode.Единственный способ добиться того, что вы хотите, — это фактически переопределить метод hashCode() для рассматриваемых объектов и гарантировать, что все они предоставляют уникальные значения.Осуществимо ли это в вашей ситуации – другой вопрос.
Для справки, я столкнулся с несколькими объектами с одним и тем же хэш-кодом по умолчанию на виртуальной машине IBM, работающей на сервере WAS.У нас была ошибка, из-за которой объекты, помещаемые в удаленный кеш, из-за этого перезаписывались.В тот момент это стало для меня откровением, поскольку я предположил, что хэш-код по умолчанию также является адресом памяти объекта.
Добавьте уникальный идентификатор ко всем вашим экземплярам, т.е.
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 и запросите это свойство.Будет безопасно внутри одной виртуальной машины (при условии, что в игру не играют с загрузчиками классов, чтобы обойти статику).
Мы можем просто скопировать код из ToString of Object Class, чтобы получить ссылку на строку
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)));
}
}