この記事では、著者はJavaの非常に重要で興味深い機能を紹介します。これは、自動ボクシングとボクシングを解除し、ソースコードからの自動ボクシングとボックス化の原則を解釈します。同時に、この機能もトラップを残します。開発者が注意を払わない場合、彼らは簡単にこのtrapに陥ります。
オートボクシング
意味
Javaプログラムを書くとき、人々はしばしば次の方法で整数オブジェクトを定義します。
整数i = 100;
上記のコードから、私はタイプの整数の参照であり、100がJava(原始データ型)の基本データ型であることがわかります。基本的なデータ型を対応するラッパークラスに直接渡すこの方法は、自動ボクシングです。
JDK 1.5では、初めて自動ボクシングが導入されました。 JDK 1.5の前に、値が100の整数オブジェクトを定義する場合は、これを行う必要があります。
整数i = new Integer(100);
原理
上記のコード「Integer i = 100;」でブレークポイントを作成しましょう。そしてそれに従ってください。
次に、プログラムが整数クラスのValueof(int i)メソッドにジャンプすることがわかります。
/** *指定された * <tt> int </tt>値を表す<tt> integer </tt>インスタンスを返します。 *新しい<tt> integer </tt>インスタンスが不要な場合、この方法は通常、コンストラクター * {@link #integer(int)}を優先して使用する必要があります。 * * @param i an <code> int </code>値。 * @return a <tt> integer </tt> <tt> i </tt>を表すインスタンス。 * @since 1.5 */ public static integer valueof(int i){if(i> = -128 && i <= integercache.high)return integercache.cache [i + 128];それ以外の場合は、新しい整数(i)を返します。 }言い換えれば、梱包はJDKであり、integer.valueof(100)への呼び出しを完了するのに役立ちます。
ボクシングアンボクシング
意味
integer integer100 = 100; int int100 = integer100;
上記のコードから、integer100はタイプ整数への参照であり、int100はタイプintのプリミティブデータ型であることがわかります。ただし、対応する元のデータ型の変数に整数型オブジェクトを割り当てることができます。これはボクシングを解除しています。
ボックス化は梱包の反対です。ボクシングは、対応するカプセル化されたクラスにプリミティブデータ型を割り当てる変数です。ボックス化とは、カプセル化されたクラスの変数を、対応する元のデータ型の変数に割り当てることを意味します。梱包とアンボックスの名前も非常に適切です。
原理
私は誰もが、ボックス化プロセス中にJDKが私たちのためにしたことを推測していると信じています。実験を通して私たちの推測を証明しましょう。
上記のコードの2行目にブレークポイントを設定します。つまり、「int int100 = integer100;」のブレークポイントを設定します。そしてそれに従ってください。
プログラムがIntegerのintvalue()メソッドにジャンプすることがわかります。
/** *この<codeger </code>の値を * <code> int </code>として返します。 */ public intvalue(){return値; }つまり、JDKはintvalue()メソッドへの呼び出しを完了するのに役立ちます。上記の実験では、integer100のintvalue()メソッドを呼び出し、その返品値をINT100に割り当てることです。
拡張
実験1
integer integer400 = 400; int int400 = 400; system.out.println(integer400 == int400);
上記のコードの3行目では、integer400およびint400が==実行されます。そして、これら2つは異なるタイプの変数です。 integer400はボクシングを解除していますか、それともint400パッキングですか?操作の結果は何ですか?
==操作は、2つのオブジェクトのアドレスが等しいかどうか、または2つの基本データ型の値が等しいかどうかを判断することです。したがって、integer400がボックス化されていない場合、2つの基本的なタイプの値が比較され、実行結果が現時点で真実でなければならないことを意味すると推測するのは簡単です。 INT400が梱包されている場合、2つのオブジェクトのアドレスが等しく、この時点で実行結果が偽でなければならないことを意味します。 (著者がそれらを400に割り当てる理由については、後で説明するトラップに関連しています)。
実際の実行結果は真です。したがって、Integer400のボクシングでした。コード追跡の結果はこれを証明しています。
実験2
integer integer100 = 100; int int100 = 100; system.out.println(integer100.equals(int100));
上記のコードの3行目では、integer100のメソッドのパラメーターがINT100です。 equalsメソッドのパラメーターは、基本的なデータ型ではなくオブジェクトであることがわかっているため、ここではINT100パックされている必要があります。コード追跡の結果はこれを証明しています。
実際、メソッドのパラメータータイプが元のデータ型であり、渡されたパラメータータイプがそのカプセル化クラスである場合、自動的にボックス化されません。したがって、メソッドのパラメータータイプがカプセル化タイプであり、渡されたパラメータータイプが元のデータ型である場合、自動的にボックス化されます。
実験3
integer integer100 = 100; int int100 = 100; long long200 = 200l; system.out.println(integer100 + int100); system.out.println(long200 ==(integer100 + int100)); system.out.println(long200.equals(integer100 + int100));
最初の実験では、基本的なデータ型がカプセル化クラスで==操作を実行すると、カプセル化クラスがボックス化されていないことがわかりました。もし +、 - 、 *、 /?この実験では知ることができます。
+操作の場合、基礎となるデータ型がボックス化されます。
•4行目では、integer100+int100は、integer 200型のオブジェクトoを取得し、このオブジェクトのtoString()メソッドを実行し、「200」を出力します。
•5行目では、integer100+int100はタイプ整数と200の値のオブジェクトoを取得します。==操作は、このオブジェクトをLong200オブジェクトと比較します。明らかに、falseは出力されます。
•6行目では、integer100+int100はタイプ整数のオブジェクトoを取得し、値200の値を取得します。ロングの等しいメソッドは、両方が異なる型のカプセル化されたクラスであるため、出力が偽です。
+操作の場合、カプセル化クラスはボックス化されません。
•4行目では、integer100+int100は、int intと値200の基本データ型Bを取得し、次にボックスBを取得してoを取得し、このオブジェクトのtoString()メソッドを実行し、「200」を出力します。
•5行目では、integer100+int100は型intと値200の基本データ型B1を取得します。明らかにb1 == b2、および出力は真です。
•6行目では、integer100+int100はタイプintと値200の基本データ型Bを取得します。ロングのメソッドボックスbに等しいが、ボクシングはタイプ整数のオブジェクトoになります。oとlong200は異なるタイプのオブジェクトであるため、出力は偽です。
プログラムが実行された結果は次のとおりです。
200
真実
間違い
したがって、2番目の推測は正しいです。つまり、 +操作中にカプセル化クラスはボックス化されません。
トラップ
トラップ1
integer integer100 = null;
int int100 = integer100;
これらの2行のコードは完全に合法であり、完全にコンパイルできますが、実行すると、nullポインターの例外がスローされます。その中でも、integer100はタイプの整数のオブジェクトであり、もちろんnullを指すことができます。ただし、2行目では、integer100はボックス化されていません。つまり、intvalue()メソッドがnullオブジェクトで実行され、もちろん、nullポインターの例外がスローされます。したがって、ボクシングを解除するときは、カプセル化されたクラスオブジェクトがnullであるかどうかに特に注意を払う必要があります。
トラップ2
整数i1 = 100;
整数i2 = 100;
整数i3 = 300;
整数i4 = 300;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
I1、I2、I3、およびI4はすべて整数型であるため、実行結果は偽であると考えています。ただし、実際の実行結果は「system.out.println(i1 == i2);」です。これは本当ですが、「System.out.println(i3 == i4);」これは間違っています。これは、2つの整数型I1とI2の参照が同じオブジェクトを指し、I3とI4が異なるオブジェクトを指すことを意味します。なぜ?それらはすべて、integer.valueof(int i)メソッドと呼ばれていませんか?
integer.valueof(int i)メソッドをもう一度見てみましょう。
/** *指定された * <tt> int </tt>値を表す<tt> integer </tt>インスタンスを返します。 *新しい<tt> integer </tt>インスタンスが不要な場合、この方法は通常、コンストラクター * {@link #integer(int)}を優先して使用する必要があります。 * * @param i an <code> int </code>値。 * @return a <tt> integer </tt> <tt> i </tt>を表すインスタンス。 * @since 1.5 */ public static integer valueof(int i){if(i> = -128 && i <= integercache.high)return integercache.cache [i + 128];それ以外の場合は、新しい整数(i)を返します。 }i> = -128およびi <= integercache.highの場合、integercache.cache [i + 128]が直接返されることがわかります。その中で、integercacheは整数の内部静的クラスであり、その元のコードは次のとおりです。
private static class integercache {static final int high;静的最終整数キャッシュ[]; static {final int low = -128; //高い値は、プロパティint h = 127で構成できます。 if(integercachehighpropvalue!= null){//ここでlong.decodeを使用して、// integerの自動ボクシングキャッシュを初期化する必要がある方法を呼び出さないようにします。 i = math.max(i、127); //最大配列サイズは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(){}}IntegerCacheには、256の要素を持つ配列である静的なメンバー変数キャッシュがあることが明確にわかります。キャッシュはintegercacheで初期化されます。つまり、i番目の要素はI-128の値を持つ整数オブジェクトです。 -128〜127は最も一般的に使用される整数オブジェクトであり、このアプローチはパフォーマンスも大幅に向上させます。このため、「integeri1 = 100; integer i2 = 100;」、i1およびi2が同じオブジェクトを取得します。
拡張機能の2番目の実験を比較すると、カプセル化クラスが基本タイプで==を実行している場合、カプセル化クラスはボックスを解除し、ボクシングの結果を基本タイプと比較することがわかりました。 2つのカプセル化クラスが他のオブジェクトで==を実行している場合、2つのオブジェクトのアドレスを比較して、2つの参照が同じオブジェクトを指しているかどうかを判断します。
上記の記事では、Javaの自動パッキングとアンボクシングとそのトラップについて簡単に説明します。そのトラップは、私があなたと共有するすべてのコンテンツです。私はそれがあなたに参照を与えることができることを願っています、そしてあなたがwulin.comをもっとサポートできることを願っています。