47

私はJavaの初心者です。現在、equals と == と equals と toString の再定義について勉強しています。

再定義した toString メソッドと、Object クラスから継承したデフォルト メソッドの両方を使用したいと考えています。

そのメソッドに到達するためにそのスーパー修飾子を使用できませんでした。

これは教育目的のみです。私のコードのコメントを見ていただければ、私が得たいことはより明確になります。

ここで私を助けてくれませんか?

私のコードは次のとおりです。

public class EqualTest{
    public static void main(String[] args){ 
        Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
            //System.out.super.println(alice1);

        Employee alice2 = alice1;
            //System.out.super.println(alice2);

        Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
            //System.out.super.println(alice3);

        System.out.println("alice1==alice2: " + (alice1==alice2));
        System.out.println("alice1 == alice3: " + (alice1==alice3));
        System.out.println("alice1.equals(alice3): " + alice1.equals(alice3));
    }
}

class Employee{
...
    public String toString(){
        return getClass().getName() + "[name = " + name + 
            ", salary=" + salary + ", hireDay=" + hireDay + "]";
    }

}
4

5 に答える 5

81

厳密に言えば、純粋な Java でオブジェクトのアドレスを出力することはできません。によって生成される String 内のオブジェクト アドレスのように見える数値Object.toString()は、オブジェクトの「ID ハッシュコード」です。オブジェクトの現在のアドレスに関連している場合と関連していない場合があります。

  • 仕様には、ID ハッシュコード番号の計算方法は記載されていません。意図的に未指定のままにしています。

  • 数値はハッシュコードなので変更できませんそのため、(通常) オブジェクト アドレスに関連していますが、それは、ハッシュコードが最初にアクセスされたときのオブジェクトのアドレスになります。これは現在のアドレスとは異なる可能性がありオブジェクトの ID ハッシュコードが最初に観測されてから GC がオブジェクトを移動した場合は異なります。

  • 64 ビット JVM (ヒープ サイズが十分に大きく、圧縮 oops を使用していない) では、アドレスは、. として返される ID ハッシュコード番号に収まりませんint

とにかく、この番号を取得する方法は に電話することSystem.identityHashCode(obj)です。


オブジェクトの現在のアドレスが本当に必要な場合は、JNI とネイティブ メソッド (およびいくつかの抽象化の中断) を使用するか、Unsafeクラスのメソッドを使用して取得できます ( How can I get the memory location of a object in java? を参照)。ただし、これらのアプローチはどちらも移植性がないことに注意してください。また、それらが提供するオブジェクトアドレスは、GC の実行時に「壊れる」傾向があり、多くの (おそらくほとんどの) 潜在的なユースケースで問題になります。


疑う人のために、これはJava 10 javadocsが「ハッシュコード!=アドレス」ポイントで言うことです:

「(hashCodeは、ある時点でオブジェクトのメモリアドレスの関数として実装される場合と実装されない場合があります。)」

強調が追加されました。実際、最近の JVM では、デフォルトの動作は hashCode をメモリ アドレスに基づかないことです。少なくともJava 7以降はそうです。

これを確認する-XX:+PrintFlagsFinal には、hashcodeフラグのデフォルト値をインクルードして確認し、OpenJDK ソース コードを調べてその意味を確認します。(コードは、一部のバージョンでは「vm/runtime/synchronizer.cpp」ファイルにありますが、YMMV です。)

于 2013-08-23T07:18:42.143 に答える
19

toString()ある種のデフォルトの動作を実現したい場合は、System.identityHashCode()メソッドを利用できます。デフォルトtoString()は次のようになります。

public String toString(Object o) {
    return o.getClass().getName() + "@" + 
           Integer.toHexString(System.identityHashCode(o));
}
于 2013-08-23T07:15:01.757 に答える
1

super() メソッドを呼び出して、対応するスーパークラス メソッドを実行できます。

class Employee{
...
    public String toString(){
         String s = super.toString();
        return getClass().getName() + "[name = " + name + 
            ", salary=" + salary + ", hireDay=" + hireDay + "]" + s;
    }

Object クラスの toString() は次のとおりです。

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
于 2013-08-23T07:14:28.460 に答える
0

equals と hashcode のオーバーライドに関する詳細な回答を次に示します。

Java で equals と hashCode をオーバーライドする場合、どのような問題を考慮する必要がありますか?

重要な点は、2 つの方法の関係は次のとおりです。

a.equals(b) の場合、a.hashCode() は b.hashCode() と同じでなければなりません。

于 2013-08-23T07:15:00.270 に答える
0

Employee クラス内に別のメソッドを作成して、スーパー toString メソッドを使用することができます。

例を参照してください:

public class Employee {
    public String toString() {
        return "MyToStringMethod";
    }

    public String superToString() {
        return super.toString();
    }

    public static void main(String[] args) {
        Employee b = new Employee();
        System.out.println(b);
        System.out.println(b.superToString());
    }
}

または両方を 1 つの方法で結合します。

public class Employee {
    public String toString() {
        return super.toString() + " MyToStringMethod";
    }

    public static void main(String[] args) {
        Employee b = new Employee();
        System.out.println(b);
    }
}
于 2013-08-23T07:17:56.550 に答える