ホームページ  >  記事  >  Java  >  Java のボックス化とアンボックス化についての深い理解

Java のボックス化とアンボックス化についての深い理解

高洛峰
高洛峰オリジナル
2017-01-24 14:03:451423ブラウズ

自動ボックス化とボックス化解除の問題は Java ではよくある問題です。今日はボックス化とボックス化解除に関するいくつかの問題を見ていきます。この記事では、最初に梱包と開梱に関する最も基本的な事項について説明し、その後、書面面接でよく遭遇する梱包と開梱に関連する質問を見ていきます。

1. 梱包とは何ですか?開梱とは何ですか?

前の記事で述べたように、Java は基本データ型ごとに対応するラッパー型を提供しますが、ここでは詳しく説明しません。見つかった。 Java SE5 より前では、値 10 の整数オブジェクトを生成したい場合は、次の手順を実行する必要があります:

Integer i = new Integer(10);

Java SE5 以降、値の整数オブジェクトを生成したい場合は、オートボクシング機能が提供されています。必要なのはこれだけです:

Integer i = 10;

このプロセスでは、対応する Integer オブジェクトが値 (ボックス化) に基づいて自動的に作成されます。

それでは、開封とは何ですか?名前が示すとおり、ボックス化に対応し、ラッパー型を基本データ型に自動的に変換することを意味します。

Integer i = 10; //装箱
int n = i; //拆箱

簡単に言うと、ボックス化とは、基本データ型をラッパー型に自動的に変換することを意味します。基本データ型に変換します。

次の表は、基本的なデータ型に対応するラッパーの型を示しています:

Java のボックス化とアンボックス化についての深い理解

2. ボックス化とアンボックス化がどのように実装されるか

前のセクションでボックス化の基本概念を理解した後、このセクションでそれについて学びましょうセクション ボックス化とアンボックス化がどのように実装されるかを見てみましょう。

Interger クラスを例として、コードの一部を見てみましょう:

public class Main {
public static void main(String[] args) {
Integer i = 10;
int n = i;
}
}

クラス ファイルを逆コンパイルすると、次の内容が得られます。逆コンパイルで得られたバイトコードの内容、ボクシング時に自動的に呼び出されるのがIntegerのvalueOf(int)メソッドです。アンボックス時に自動的に呼び出されるのは、Integer の intValue メソッドです。

Java のボックス化とアンボックス化についての深い理解Double や Character など、他のものでも同様です。信じられない場合は、手動で試してみてください。


したがって、ボックス化とアンボックス化の実装プロセスは 1 つの文に要約できます:


ボックス化プロセスはラッパーの valueOf メソッドを呼び出すことによって実装され、アンボックス化プロセスはラッパーの xxxValue メソッドを呼び出すことによって実装されます。 (xxxは対応する基本データ型を表します)。


3. 面接に関する質問


ほとんどの人は梱包と開梱の概念については明確ですが、面接や筆記試験で梱包と開梱に関する質問に遭遇すると、答えることができない場合があります。 。梱包/開梱に関するよくある面接の質問をいくつか紹介します。


1. 次のコードの出力は何ですか?

public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}


おそらく、友人の中には false が出力されると言う人もいるでしょうし、true が出力されると言う人もいるでしょう。しかし実際には、出力結果は次のようになります:

tru​​e

false


なぜこの結果が表示されるのでしょうか?出力は、i1 と i2 が同じオブジェクトを指しているのに対し、i3 と i4 は異なるオブジェクトを指していることを示しています。この時点では、ソース コードを見るだけで真実を知ることができます。次のコードは、Integer の valueOf メソッドの具体的な実装です:

public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}


そして、IntegerCache クラスの実装は次のとおりです。

これらの 2 つの段落から コードからわかるように、valueOf メソッドを通じて Integer オブジェクトを作成するとき、値が [-128,127] の間にある場合、IntegerCache.cache にすでに存在するオブジェクトへの参照は次のようになります。それ以外の場合は、新しい Integer オブジェクトが作成されます。

上記のコードでは、i1 と i2 の値は 100 であるため、既存のオブジェクトはキャッシュから直接フェッチされるため、i1 と i2 は同じオブジェクトを指しますが、i3 と i4 は異なるオブジェクトを指しますそれぞれオブジェクト。

2. 次のコードの出力は何でしょうか?

private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer&#39;s autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}


出力結果が上記の質問と同じであると考える友人もいるかもしれませんが、実際はそうではありません。実際の出力結果は次のようになります。

false

false

具体的な理由については、読者は Double クラスの valueOf の実装を確認できます。


ここでは、Double クラスの valueOf メソッドが Integer クラスの valueOf メソッドとは異なる実装を使用する理由についてのみ説明します。それは簡単です。特定の範囲内の整数値の数は有限ですが、浮動小数点数は有限ではありません。

Integer、Short、Byte、Character、および Long クラスの valueOf メソッドの実装は似ていることに注意してください。 Java のボックス化とアンボックス化についての深い理解

Double と Float の valueOf メソッドの実装は似ています。

3. 次のコードの出力結果は次のとおりです:

public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}


出力結果は次のとおりです:

tru​​e

true

至于为什么是这个结果,同样地,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:

public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}

   

而其中的 TRUE 和FALSE又是什么呢?在Boolean中定义了2个静态成员属性:

public static final Boolean TRUE = new Boolean(true);
/**
* The <code>Boolean</code> object corresponding to the primitive
* value <code>false</code>.
*/
public static final Boolean FALSE = new Boolean(false);

   

至此,大家应该明白了为何上面输出的结果都是true了。

4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。

当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:

1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;

2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

5.下面程序的输出结果是什么?

public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d);
System.out.println(e==f);
System.out.println(c==(a+b));
System.out.println(c.equals(a+b));
System.out.println(g==(a+b));
System.out.println(g.equals(a+b));
System.out.println(g.equals(a+h));
}
}

   

先别看输出结果,读者自己想一下这段代码的输出结果是什么。这里面需要注意的是:当 “==”运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然:

true
false
true
true
true
false
true

第一个和第二个输出结果没有什么疑问。第三句由于 a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。

以上所述是小编给大家介绍的Java のボックス化とアンボックス化についての深い理解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网站的支持!

更多Java のボックス化とアンボックス化についての深い理解相关文章请关注PHP中文网!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。