Java のボックス化とアンボックス化の詳細な説明
前書き:
ボックス化とアンボックス化の概念を理解するには、Java データ型を理解する必要があります
ボックス化: 基本型を対応する参照型でラップして、オブジェクトの性質を持たせる。 Int は Integer にパッケージ化され、float は Float にパッケージ化されます
Unboxing: ボックス化とは逆に、参照型オブジェクトは値型 data に単純化されます
Integer a = 100; 这是自动装箱 (编译器调用的是static Integer valueOf(int i)) int b = new Integer(100); 这是自动拆箱
次のコード部分を見てください
m1
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m11(); dt.m12(); } public void m11() { Integer a = new Integer(100); Integer b = 100; System.out.println("m11 result " + (a == b)); } public void m12() { Integer a = new Integer(128); Integer b = 128; System.out.println("m12 result " + (a == b)); } }
印刷結果は?
m11 result false m12 result false
"== はアドレスを比較し、2 つのオブジェクト a と b のアドレスは異なります。つまり、これらは 2 つのオブジェクトであるため、どちらも false です
javap を通じてバイトコードを解析します。内容は次のとおりです
public void m11(); Code: 0: new #44; //class java/lang/Integer 3: dup 4: bipush 100 6: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 9: astore_1 10: bipush 100 12: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 15: astore_2 16: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 19: new #59; //class java/lang/StringBuilder 22: dup 23: ldc #61; //String m11 result 25: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 28: aload_1 29: aload_2 30: if_acmpne 37 33: iconst_1 34: goto 38 37: iconst_0 38: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 41: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 44: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 47: return public void m12(); Code: 0: new #44; //class java/lang/Integer 3: dup 4: sipush 128 7: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 10: astore_1 11: sipush 128 14: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 17: astore_2 18: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 21: new #59; //class java/lang/StringBuilder 24: dup 25: ldc #82; //String m12 result 27: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 30: aload_1 31: aload_2 32: if_acmpne 39 35: iconst_1 36: goto 40 39: iconst_0 40: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 43: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 46: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 49: return </init></init></init></init>
m2
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m21(); dt.m22(); } public void m21() { Integer a = new Integer(100); Integer b = new Integer(100); System.out.println("m21 result " + (a == b)); } public void m22() { Integer a = new Integer(128); Integer b = new Integer(128); System.out.println("m22 result " + (a == b)); } }
出力された結果は
m21 result false m22 result false
a と b は依然として 2 つのオブジェクトです
javap内容
すごい
m3
public void m21(); Code: 0: new #44; //class java/lang/Integer 3: dup 4: bipush 100 6: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 9: astore_1 10: new #44; //class java/lang/Integer 13: dup 14: bipush 100 16: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 19: astore_2 20: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 23: new #59; //class java/lang/StringBuilder 26: dup 27: ldc #84; //String m21 result 29: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 32: aload_1 33: aload_2 34: if_acmpne 41 37: iconst_1 38: goto 42 41: iconst_0 42: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 45: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 48: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 51: return public void m22(); Code: 0: new #44; //class java/lang/Integer 3: dup 4: sipush 128 7: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 10: astore_1 11: new #44; //class java/lang/Integer 14: dup 15: sipush 128 18: invokespecial #46; //Method java/lang/Integer."<init>":(I)V 21: astore_2 22: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 25: new #59; //class java/lang/StringBuilder 28: dup 29: ldc #86; //String m22 result 31: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 34: aload_1 35: aload_2 36: if_acmpne 43 39: iconst_1 40: goto 44 43: iconst_0 44: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 47: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 50: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 53: return
結果の印刷
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m31(); dt.m32(); } public void m31() { Integer a = 100; Integer b = 100; System.out.println("m31 result " + (a == b)); } public void m32() { Integer a = 128; Integer b = 128; System.out.println("m32 result " + (a == b)); } }
最初のものが真で、二番目のものが偽なのはなぜですか? javap によって解析されたデータを観察します
javap 解析されたコンテンツ
m31 result true m32 result false
m4
public void m31(); Code: 0: bipush 100 2: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 5: astore_1 6: bipush 100 8: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 11: astore_2 12: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 15: new #59; //class java/lang/StringBuilder 18: dup 19: ldc #88; //String m31 result 21: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 24: aload_1 25: aload_2 26: if_acmpne 33 29: iconst_1 30: goto 34 33: iconst_0 34: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 37: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 40: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 43: return public void m32(); Code: 0: sipush 128 3: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 6: astore_1 7: sipush 128 10: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 13: astore_2 14: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 17: new #59; //class java/lang/StringBuilder 20: dup 21: ldc #90; //String m32 result 23: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 26: aload_1 27: aload_2 28: if_acmpne 35 31: iconst_1 32: goto 36 35: iconst_0 36: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 39: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 42: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 45: return
結果を印刷する
public class DataType { public static void main(String args[]) { DataType dt = new DataType(); dt.m41(); dt.m42(); } public void m41() { Integer a = Integer.valueOf(100); Integer b = 100; System.out.println("m41 result " + (a == b)); } public void m42() { Integer a = Integer.valueOf(128); Integer b = 128; System.out.println("m42 result " + (a == b)); } }
javap parsed content
m41 result true m42 result false
分析
javap Java コンパイラによって生成されたバイトコードを逆コンパイルして表示できるツールが付属しています (上記のコードは javap -c DataType のみを使用しています)。コードを分析するための優れたツールです。詳しい使用方法については、Google で調べてください。
まず、m4 を見てください。実行結果に「true」が表示されるのはなぜですか? true は、a と b が同じオブジェクトであることを意味します。
しかし、オブジェクト a は Integer.valueOf() を呼び出して生成され、オブジェクト b は自動ボックス化によって生成されるのはなぜでしょうか。バイトコードをもう一度見てみましょう。結局のところ、Java プログラムはバイトコードを実行する仮想マシンに依存して実装されています。
m41 このメソッドは valueOf() を 1 回だけ適用しますが、バイトコード内に 2 回現れます。これは、valueOf() がオートボクシング中にも呼び出されることを示しています。
以下は valueOf() の具体的な実装です
public void m41(); Code: 0: bipush 100 2: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 5: astore_1 6: bipush 100 8: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 11: astore_2 12: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 15: new #59; //class java/lang/StringBuilder 18: dup 19: ldc #92; //String m41 result 21: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 24: aload_1 25: aload_2 26: if_acmpne 33 29: iconst_1 30: goto 34 33: iconst_0 34: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 37: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 40: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 43: return public void m42(); Code: 0: sipush 128 3: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 6: astore_1 7: sipush 128 10: invokestatic #49; //Method java/lang/Integer.valueOf:(I)Ljava/lang/In teger; 13: astore_2 14: getstatic #53; //Field java/lang/System.out:Ljava/io/PrintStream; 17: new #59; //class java/lang/StringBuilder 20: dup 21: ldc #94; //String m42 result 23: invokespecial #63; //Method java/lang/StringBuilder."<init>":(Ljava/la ng/String;)V 26: aload_1 27: aload_2 28: if_acmpne 35 31: iconst_1 32: goto 36 35: iconst_0 36: invokevirtual #66; //Method java/lang/StringBuilder.append:(Z)Ljava/la ng/StringBuilder; 39: invokevirtual #70; //Method java/lang/StringBuilder.toString:()Ljava/l ang/String; 42: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/St ring;)V 45: return }
[-128, 127] の間の数値、valueOf はキャッシュ内のオブジェクトを返すため、2 つの呼び出しは同じオブジェクトを返します。
読んでいただきありがとうございます、皆さんのお役に立てれば幸いです、このサイトをサポートしていただきありがとうございます!
Java のボックス化とアンボックス化の詳細な説明とサンプル コード関連の記事については、PHP 中国語 Web サイトに注目してください。