JAva Integer自動包装と解包

5855 ワード

Javaの自動梱包メカニズムについてはご存知でしょうが、一般的にこれらのメカニズムは、基本タイプデータをコンテナに格納する際に使用されます.コンテナには基本タイプデータの存在が許されないため、自動梱包メカニズムを呼び出し、基本データタイプをオブジェクトに変換し、基本データをオブジェクトに保存し、基本方法を提供します.しかし、自動包装メカニズムにはいくつかの落とし穴があり、適切に使用しないとエラーになります.
まず次の例を見てみましょう
 1 package test;
 2 
 3 public class AutoPack {
 4     public static void main(String[] args) {
 5         Integer a=1;
 6         Integer b=2;
 7         Integer c=3;
 8         Integer d = 3;
 9         Integer e=321;
10         Integer f=321;
11         Long g=3L;
12         System.out.println(c==d);//true
13         System.out.println(e==f);//false
14         System.out.println(c==(a+b));//true
15         System.out.println(c.equals(a+b));//true
16         System.out.println(g==(a+b));//true
17         System.out.println(g.equals(a+b));//false  //      
18         System.out.println(g.equals((long)(a+b)));//true              ,    
19     }
20 }

上記の例の出力はすべて正しいですか?もし疑問があれば、私の次の答えを見てください.
まず、オブジェクトタイプについて、==記号は比較オブジェクトの物理アドレスを表し、equalsメソッドはオブジェクトの値(両方が同じオブジェクトタイプに属することを前提とする)を比較し、基本データタイプについて==記号は値を比較する
次にIntegerの内部実装を見てみましょう.Integerには3つの作成方法があります.それぞれ
Integer a = new Integer(1);  //     

Integer b = Integer.valueOf(2);  

Integer c = 3;    //    ,   valueOf  

上記の3つの方法のうち、1つ目の方法は新しいIntegerオブジェクトを作成します.このようなオブジェクトは==で比較するときに必ず異なり、equalsメソッドでしか比較できません.
2つ目のメソッドと3つ目のメソッドは、ValueOfメソッドを明示的または暗黙的に呼び出しているので、ValueOfメソッドを見てみましょう.
   public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

valueOf法は、まず、low(-128)より大きく、数字(127)より小さいか否かを判断し、条件が満たされると、この数をIntegerCacheから直接返します(IntegerCacheは、重複作成を防止するために一般的な数を格納するために使用されます).
したがって、valueOfまたはInteger=numの2つの方法で作成されたオブジェクトの値が127未満で-128より大きい場合、==比較を行ってもequals比較を行ってもtrueになります.
この範囲を満たさない数については、どのように作成しても新しいオブジェクトであり、equalsでしか比較できません.次にequalsメソッドを見てみましょう.
 
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

equalsは簡単で、まず両者のタイプが一致しているかどうかを比較し、タイプが一致していない場合はfalseを直接返し、そうでない場合は両者の値を比較し、同じ場合はtrueを返します.
では、今振り返って上の出力を見てみると、はっきりしているのではないでしょうか.
もう一つは上の3番目と5番目の出力です.等式の両方に算術演算子が使われているので、自動的にパケットを分解します.パケットを分解して比較するのは両者のvalueです.
 
では、以下にまとめてみましょう.
1.==演算の場合、両端のいずれかの端に算術式が含まれている場合、自動的にパケットが解除されます.この場合、値が比較されます.
2.==演算の場合、両端に算術式がないと解包されないので、対象のアドレスを比較します(これは危険です)
3.equalsはオブジェクトの値を比較して使用することができますが、同じオブジェクトタイプを前提としています.たとえば、上から2番目の出力では、値は等しいですが、1つはIntegerで、1つはLongで、falseを返しますが、基本データ型intとlongであれば、実際には等しいことができます.
4.IntegerにIntegerCacheがあり、-128~127の値がキャッシュされるため、この範囲内でnewキーでIntegerオブジェクトを作成しない限り、これらのオブジェクトは同じオブジェクトになります