23

Javaの扱い方==equals()、その他の種類の数値については少し混乱しています。例えば:intInteger

Integer X = 9000;
int x = 9000;
Short Y = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
// results.add(X == Y); DOES NOT COMPILE        1)
results.add(Y == 9000);                      // 2)
results.add(X == y);                         // 3)
results.add(X.equals(x));                    // 4)
results.add(X.equals(Y));                    // 5)
results.add(X.equals(y));                    // 6)
System.out.println(results);

出力(多分あなたは最初にあなたの推測をするべきです):

[true, true, true, false, false]
  1. X == Y異なるオブジェクトであるため、コンパイルされないことが予想されます 。
  2. 9がデフォルトでであり、1)がコンパイルさえされていないことを考えると、私は少し驚いてY == 9います。を期待するメソッドにを入れることはできませんが、ここではそれらは等しいことに注意してください。trueintintShort
  3. これは2つと同じ理由で驚くべきことですが、もっと悪いようです。
  4. xとに自動ボックス化されているので、当然のことIntegerです。
  5. 当然のことながら、異なるクラスのオブジェクトはであってはなりませんequal()
  6. 何?? X == yですtrueが?X.equals(y)_ 常により厳密にfalseすべきではありませんか?==equals()

誰かが私がこれを理解するのを手伝ってくれるなら、私はそれを感謝します。==とequals()はどのような理由でこのように動作しますか?

編集: この動作が-128から127までの整数の動作とは関係がないことを示すために、9を9000に変更しました。

2番目の編集: わかりました。このことを理解していると思われる場合は、念のため、次のことを検討する必要があります。

Integer X = 9000;
Integer Z = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
results.add(X == Z);                      // 1)
results.add(X == y);                      // 2)
results.add(X.equals(Z));                 // 3)
results.add(X.equals(y));                 // 4)
System.out.println(results);

出力:

[false, true, true, false]

その理由は、私が理解している限りでは次のとおりです。

  1. 別のインスタンス、とても違う。
  2. Xボックス化されていない場合は同じ値なので、等しい。
  3. 同じ値なので、等しい。
  4. yボックス化するIntegerことはできないので、等しくすることはできません。
4

8 に答える 8

22

(小さい)整数インスタンスがキャッシュされるため、不変のx == yが小さいインスタンスに対して保持されます(実際には-127 +128、JVMによって異なります)。

Integer a = 10;
Integer b = 10;

assert(a == b); // ok, same instance reused

a = 1024;
b = 1024;

assert(a == b); // fail, not the same instance....
assert(a.equals(b)); // but same _value_

編集

4)および5)は、equalsチェックタイプXが整数であるのに対し、Yはショートであるため、falseを生成します。これはjava.lang.Integer#equalsメソッドです。

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }

    return false;
}
于 2009-08-11T11:13:05.560 に答える
13

の理由

X == y

trueであるということは、2進数の昇格と関係があります。等式演算子の少なくとも1つのオペランドが数値タイプに変換可能な場合、数値等式演算子が使用されます。まず、最初のオペランドがボックス化されていません。次に、両方のオペランドがに変換されintます。

その間

X.equals(y)

通常の関数呼び出しです。すでに述べたようyに、オブジェクトに自動ボックス化されShortます。Integer.equals引数がインスタンスでない場合は、常にfalseを返しIntegerます。これは、実装を調べることで簡単に確認できます。

これは設計上の欠陥であると主張する人もいるかもしれません。

于 2009-08-11T11:26:41.463 に答える
7

物語の教訓:

タイププロモーションと同様に、オートボクシング/アンボクシングは混乱を招きます。一緒に、それらは良いなぞなぞを作りますが、恐ろしいコードです。

実際には、intよりも小さい数値型を使用することはほとんど意味がなく、すべてのautoboxingと-unboxingにエラーとしてフラグを立てるようにeclipseコンパイラーを構成する傾向があります。

于 2009-08-11T11:34:00.543 に答える
3

ここでの問題は、==の処理方法だけでなく、オートボクシングです... Yと9を比較すると、等しい2つのプリミティブを比較していますが、最後の2つのケースでは、それが等しいという理由だけでfalseになります。2つのオブジェクトは、それらが同じ種類で同じ値を持つ場合にのみ等しくなります。「X.equals(y)」で言うと、Integer.equals(Short)を実行するように指示し、Integer.equals()の実装を見ると失敗します。

   public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
    }

オートボクシングのため、最後の2つは、両方ともShortsとして渡されるのと同じ失敗になります。

編集:1つ忘れました... results.add(X == y);の場合 Xのボックスを解除し、(X.intValue()== y)を実行します。これは、9==9と同様にtrueになります。

于 2009-08-11T11:18:46.237 に答える
1

Javaは、必要に応じて整数を整数に自動的に変換します。ショートにも同じことが言えます。この機能は、自動ボクシングおよび自動アンボックスと呼ばれます。あなたはここでそれについて読むことができます。

これは、コードを実行すると次のことを意味します。

int a = 5;
Integer b = a;
System.out.println(a == b);

Javaはそれを次のように変換します。

int a = 5;
Integer b = new Integer(a);
System.out.println(a == b.valueOf());
于 2009-08-11T11:14:34.590 に答える
1

この自動変換はオートボクシングと呼ばれます。

于 2009-08-11T11:17:07.567 に答える
1

「equal(objectobj)」をオーバーライドするための良い習慣は、最初に渡されたパラメーターのタイプをチェックすることです。したがって、おそらくこれによりX.equals(Y)falseになります。あなたは真実を掘り下げるためにソースコードをチェックするかもしれません:)

于 2009-08-11T11:23:00.610 に答える
1

オートボクシングの仕組みと「小さな」値の整数オブジェクトのキャッシュ方法についてもう少し詳しく説明します。

プリミティブintが整数に自動ボックス化されると、コンパイラーはコードをInteger.valueOf(...)の呼び出しに置き換えることによってそれを行います。したがって、次のようになります。

Integer a = 10;

コンパイラによって次のように置き換えられます。

Integer a = Integer.valueOf(10);

クラスIntegerのvalueOf(...)メソッドは、-127〜128のすべての値のIntegerオブジェクトを含むキャッシュを維持します。この範囲の値でvalueOf(...)を呼び出すと、メソッドはpre-を返します。キャッシュからの既存のオブジェクト。値が範囲外の場合、指定された値で初期化された新しいIntegerオブジェクトを返します。(それがどのように機能するかを正確に知りたい場合は、JDKインストールディレクトリでファイルsrc.zipを検索し、その中のクラスjava.lang.Integerのソースコードを探します。)

さて、これを行うと:

Integer a = 10;
Integer b = 10;
System.out.println(a == b);

trueが出力されていることがわかりますが、aとbの値が同じであるためではなく、aとbが同じIntegerオブジェクトを参照しているため、キャッシュからのオブジェクトはInteger.valueOf(...)によって返されます。

値を変更した場合:

Integer a = 200;
Integer b = 200;
System.out.println(a == b);

次に、200がキャッシュの範囲外であるため、falseが出力されます。したがって、aとbは2つの異なる整数オブジェクトを参照します。

残念ながら、JavaのラッパークラスやStringなどの値型のオブジェクトの等価性に==が使用されているため、直感に反します。

于 2009-08-11T14:22:16.523 に答える