toString()とhashCode()がオーバーライドされたときに、Javaでオブジェクトの「オブジェクト参照」をどのように取得しますか?


106

デバッグの目的で、Javaでオブジェクトの「オブジェクト参照」を出力したいと思います。つまり、状況に応じてオブジェクトが同じ(または異なる)ことを確認します。

問題は、問題のクラスが別のクラスを継承していることです。これにより、通常はIDを取得するtoString()とhashCode()の両方がオーバーライドされます。

状況例:すべてのスレッドがリソースオブジェクトの同じインスタンスを使用しているかどうかを(開発中に)確認したい、マルチスレッドアプリケーションの実行。


1
あなたがそれをまったくできるかどうかに依存します... ==が進むべき道です...しかし、私は問題のコードがどのように構造化されているのかわかりません。繰り返しになりますが、hashCodeはあなたがやっていることには問題ありませんが、ライブラリの実装方法によっては壊れる可能性があります。
TofuBeer

それは本当に良い質問です。
Zhang Xiang、

回答:


108

正確に何を計画していますか(何をしたいかによって、何を呼び出す必要があるかが異なります)。

hashCodeは、JavaDocsで定義されているように述べています。

合理的に実用的である限り、Objectクラスによって定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。(これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJava™プログラミング言語では必要ありません。)

したがってhashCode()、メモリ内の一意のオブジェクトであるかどうかを確認するために使用している場合、それを行うのは良い方法ではありません。

System.identityHashCode 次のことを行います。

指定されたオブジェクトのクラスがhashCode()をオーバーライドするかどうかに関係なく、デフォルトのメソッドhashCode()によって返されるのと同じ、指定されたオブジェクトのハッシュコードを返します。null参照のハッシュコードはゼロです。

これは、あなたがしていることに対して、あなたが望むもののように聞こえます...しかし、あなたがしたいことは、ライブラリの実装方法によっては安全ではないかもしれません。


6
私はコードの値に基づいて行動していません。PRとして 私の質問編集、特定の状況のデバッグ目的でのみ使用します。ですから、私の答えは妥当だと思いますが、洞察に満ちた回答に対して+1を差し上げます。
ニコライ

1
オッズはそれが常にあなたが望むことをするでしょう-しかし、それはいくつかのVMで壊れる可能性があります。
TofuBeer

これは、妥当なVMで破損します(つまり、identityHashCodeが必ずしも一意であるとは限りません)。identityHashCodeはIDではありません
Tom Hawtin-タックライン

すでに述べたように、アドレスに基づくハッシュコードの保証はありません。WAS内のIBM VMで同じIDを持つ複数のオブジェクトが発生するのを見ました。
ロビン、

「これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されます」保証ではなく、Sunのデフォルトの実装です。s = "Hello"やt = "Hello"のようなものは、sとtが実際には同じオブジェクトであるため、同じidentityHashCodeを持つことになります。
TofuBeer

50

これは私がそれを解決した方法です:

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

5
複数のオブジェクトが同じidentityHashCodeを返す可能性があるため、これは実際には正しくありません。
ロビン、

2
同じIDハッシュを持つ2つのオブジェクト(参照)が同じオブジェクトであるというのは本当ではないでしょうか。それがOPに必要なものです
basszero

3
いいえ、それは真実ではありません。可能性は高いですが、仕様でアルゴリズムが定義されていないため、保証されません。
Robin

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からコードをコピーして、stringの参照を取得できます

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.