toString () 및 hashCode ()가 재정의되었을 때 Java에서 객체의 "객체 참조"를 어떻게 얻습니까?


106

디버깅 목적으로 Java에서 개체의 "개체 참조"를 인쇄하고 싶습니다. 즉, 상황에 따라 개체가 동일하거나 다른지 확인합니다.

문제는 해당 클래스가 일반적으로 ID를 제공하는 toString () 및 hashCode () 모두를 재정의 한 다른 클래스에서 상속된다는 것입니다.

상황 예 : 다중 스레드 응용 프로그램을 실행하는 경우 (개발 중) 모든 스레드가 리소스 개체의 동일한 인스턴스를 사용하는지 확인하려고합니다.


1
당신이 그것을 할 수 있는지에 따라 ... == 갈 길이다 ...하지만 문제의 코드가 어떻게 구조화되어 있는지 모르겠습니다. 다시 hashCode는 수행중인 작업에 적합 할 수 있지만 라이브러리 구현 방법에 따라 손상 될 수 있습니다.
TofuBeer

정말 좋은 질문입니다.
Zhang Xiang

답변:


108

정확히 무엇을 할 계획입니까 (당신이하고 싶은 일이 전화해야 할 일과 차이를 만듭니다).

hashCode는 JavaDocs에 정의 된대로 다음과 같이 말합니다.

합리적으로 실용적인만큼 Object 클래스에 의해 정의 된 hashCode 메서드는 고유 한 개체에 대해 고유 한 정수를 반환합니다. (이것은 일반적으로 객체의 내부 주소를 정수로 변환하여 구현되지만 Java ™ 프로그래밍 언어에서는이 구현 기술이 필요하지 않습니다.)

따라서 hashCode()메모리에서 고유 한 개체인지 확인하는 데 사용 하는 경우 좋은 방법이 아닙니다.

System.identityHashCode 다음을 수행합니다.

주어진 객체의 클래스가 hashCode ()를 재정의하는지 여부에 관계없이 기본 메소드 hashCode ()에 의해 반환되는 것과 동일한 해시 코드를 주어진 객체에 대해 반환합니다. 널 참조의 해시 코드는 0입니다.

당신이하고있는 일에 대해, 당신이 원하는 것처럼 들리지만 ... 당신이 원하는 것은 라이브러리가 어떻게 구현되었는지에 따라 안전하지 않을 수 있습니다.


6
나는 코드의 가치에 대해 행동하지 않습니다. 홍보로. 내 질문 편집, 특정 상황의 디버깅 목적으로 만 사용합니다. 그래서 제 답변이 합리적이라고 생각하지만 통찰력있는 답변을 위해 +1을드립니다.
Nicolai

1
항상 원하는 작업을 수행하지만 일부 VM에서는 중단 될 수 있습니다.
TofuBeer

합리적인 VM에서 중단됩니다 (즉 identityHashCode가 반드시 고유하지는 않음). identityHashCode는 ID가 아닙니다
Tom Hawtin-tackline

앞서 언급했듯이 주소를 기반으로하는 해시 코드가 보장되지 않습니다. 동일한 ID를 가진 여러 개체가 WAS 내부의 IBM VM에서 발생하는 것을 보았습니다.
Robin

"이것은 일반적으로 객체의 내부 주소를 정수로 변환하여 구현됩니다"는 보증이 아니라 Sun의 기본 구현입니다. s = "Hello"및 t = "Hello"와 같은 경우 s와 t는 실제로 동일한 객체이므로 동일한 identityHashCode를 갖게됩니다.
두부 맥주

50

이것이 내가 해결 한 방법입니다.

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

5
여러 객체가 동일한 identityHashCode를 반환 할 수 있기 때문에 이것은 실제로 올바르지 않습니다.
Robin

2
동일한 ID 해시를 가진 두 개체 (참조)가 동일한 개체라는 것이 사실이 아닙니까? 그것이 OP가 원하는 것입니다
basszero

3
아니요, 사실이 아닙니다. 가능성이 매우 높지만 사양이 알고리즘을 정의하지 않으므로 보장되지는 않습니다.
로빈

8

Double equals ==는 객체의 hashCode 또는 equals 구현에 관계없이 항상 객체 ID를 기반으로 확인합니다. 물론-비교하는 객체 참조가 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 () 메서드를 재정의하고 모두 고유 한 값을 제공하도록하는 것입니다. 이것이 귀하의 상황에서 실행 가능한지 여부는 또 다른 질문입니다.

기록을 위해 WAS 서버에서 실행되는 IBM VM에서 동일한 기본 해시 코드를 가진 여러 개체를 경험했습니다. 이로 인해 원격 캐시에 넣는 객체를 덮어 쓰는 결함이있었습니다. 기본 해시 코드가 객체 메모리 주소라고 가정했기 때문에 그 시점에서 눈을 뜨게했습니다.


2

모든 인스턴스에 고유 ID를 추가하십시오.

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)));
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.