10

私のメモで次のことを見つけましたが、私はそれを理解することができません:

プリミティブ型ラッパークラスは、限られた数の値のキャッシュを実装します。
これにより、限られた数の深く等しいラッパーオブジェクトも浅く等しくなることが保証されo1.equals( o2 )ますo1 == o2
たとえば、new Integer( 0 ) == new Integer( 0 )
一般に、これは常に機能するとは限りません。
たとえば、new Integer(666)== new Integer(666)
は成り立たない場合があります。
キャッシュの理由は、メモリを節約するためです。
一般に、キャッシュは「小さな」プリミティブ値に対して機能します。

これが何を意味するのか、または深い(.equals())と浅い(==)が等しいの違いが何であるかがわかりません。私は実際には、.equalsをオブジェクトに使用し、==を積分値に使用する必要があることを知っていますが、これの実際の理由は私をほのめかします。

浅い名前では、両方の値が同じタイプと名前であることを確認するだけで、両方の変数が同じオブジェクトを指していることを詳細に確認していると思いますか?ただし、ここでキャッシングがどのように機能するのか、なぜそれが役立つのかはわかりません。

4

5 に答える 5

9

あなたがそうするとき、あなたは==等しいかどうか参照を比較しています。これは、「メモリ内のアドレスは両方のオブジェクトで同じですか?」と言っているということです。

.equals()そうするとき、オブジェクト自体が等しいかどうかを比較しています。これは、「これらの 2 つのオブジェクトは等しいと考えていますか?」と言っているということです。

与えられた例は貧弱でした。JLS によって義務付けられているこれらの番号に対して行われる唯一のキャッシュは、.valueOf()メソッドです。コンストラクターはキャッシュされません。

さらに、JLS は、キャッシュする必要がある最小値のみを指定します [-128:127]。JVM 実装は、必要に応じてより多くをキャッシュできます。これは、一部のマシンでは発生するInteger.valueOf(500) == Integer.valueOf(500)可能性があることを意味しますが、他のマシンでは発生する可能性があります。falsetrue

class biziclop {

    public static void main(String[] args) {
        System.out.println(new Integer(5) == new Integer(5));
        System.out.println(new Integer(500) == new Integer(500));

        System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
        System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
    }
}

結果:

C:\Documents and Settings\glow\My Documents>java biziclop
false
false
true
false

C:\Documents and Settings\glow\My Documents>

ここでより詳細な回答を参照してください (コメントは宝石です!):なぜ人々はまだ Java でプリミティブ型を使用するのですか?

于 2011-04-18T13:30:45.730 に答える
8

実際、浅い/深い解剖は==/等しい解剖とは異なります。

  1. == はオブジェクトの同一性を比較します。つまり、オペランドが実際に同じかどうか (同じメモリ領域への 2 つの参照) をチェックしますが、equalsオブジェクトの等価性を比較します。同じ。2 つのオブジェクトの場合

    a == b
    

    それは本当です

    a.equals(b) // if a != null
    

    、しかしその反対はすべての場合に当てはまるわけではありません。

  2. 浅い/深い区別は、equals比較する場合にのみ意味があります。浅いとは、2 つのオブジェクトの直接の内容のみを比較して、それらが自分の意味で「等しい」かどうかを調べることを意味します。一方、深いとは、オブジェクトの内容を比較する必要がプリミティブ フィールドだけになるまで再帰的に比較することを意味します。オブジェクトのメソッドを、これらのオブジェクトのインスタンス フィールドに対するequals一連の呼び出しとして 定義する場合は、詳細な比較を使用します。 文字列などの複合型を比較す​​るために演算子を使用しequalsて定義する場合、浅い比較を使用しますが、これは Java では正しくありません。equals==

これらすべてのモラルは、2 つの複合オブジェクトを比較するために使用してはならないということです==。ただし、それらが同じである場合にのみ等しいと見なす場合は除きます。

于 2011-04-18T13:43:28.143 に答える
2

あなたが「浅い等しい」と呼ぶものは同一性です:2つの参照(つまりオブジェクト)は、それらがまったく同じインスタンスである場合、同一です。他の言語でのポインターが何であるかを知っている場合は、ID をポインターの等価性と比較できます。

あなたが「深い等しい」と呼ぶものは等しいです: 2 つのオブジェクトが返さaれたb場合は等しいです(できればその逆)。等価性の正確さは、メソッドの実装方法に強く依存します。詳細については、クラスの Javadoc を参照してください。a.equals(b)trueequalsObject

于 2011-04-18T13:31:50.883 に答える
2

最初に:new Integer(0) == new Integer(0)常に新しいオブジェクトを作成し、存在する可能性のあるオートボクシング キャッシング メカニズムを回避するため、決してに評価されません。truenew

おそらく聞いたことがあるのは、オートボクシング (つまり、必要に応じてプリミティブ値をそれぞれのラッパー クラスに自動的に変換すること) でした。valueOf()オートボクシングは、ラッパー クラスメソッドを使用してアクセスできるメカニズムを使用します。intつまり、 anから an への自動ボクシングは、のInteger呼び出しとほとんど同じように機能しInteger.valueOf(int)ます。

Integer.valueOf(0) == Integer.valueOf(0) true一般的な値 (つまり、絶対値が小さい値) がキャッシュされるため、は に評価されます。2 回続けて呼び出すと、同じ Integerオブジェクトが取得されます。valueOf(0)これは、より高い値 (例では 666 など) では必ずしも当てはまりません。

于 2011-04-18T13:33:33.593 に答える
1

equals() は、2 つのオブジェクトが本質的に同じかどうかをテストしますが、2 つの異なるオブジェクトに対して true を返すことができます。つまり、2 つの異なるペーパー クリップは「等しい」ものです。参照タイプの "==" は、2 つの参照が同じオブジェクトを参照しているかどうかをテストします。つまり、ペーパー クリップはそれ自体に対してのみ == です。== は同一性equalsテストし、同等性をテストします。

0 を持つ 2 つの異なる Integer オブジェクトを持つことができます (それらは ですequals())。キャッシュとは、オブジェクトを保存し、可能な場合はそれらを再利用することを意味します。

于 2011-04-18T13:31:10.737 に答える