JavaRush /Java Blog /Random-JA /Java でのオートボックス化とボックス化解除
Viacheslav
レベル 3

Java でのオートボックス化とボックス化解除

Random-JA グループに公開済み
<h2>はじめに</h2>プログラミング言語は、人々が話す言語と同じように、生きて変化し、言語をより使いやすくするために新しい現象が現れます。そしてご存知のとおり、言語は私たちの考えを便利に表現するものでなければなりません。
Java でのオートボックス化とアンボックス化 - 1
そこで、Java SE 5 では、ボックス化/アンボックス化メカニズムが導入されました。また、Oracle の別のチュートリアルでは、思考を表現するこの手段であるオートボックス化とアンボックス化の機能について説明しています。<h2>自動パッキング ボクシング</h2>自動パッキング ボクシングの例を見てみましょう。まず、それがどのように機能するかを見てみましょう。サイトcompilejava.netを使用してクラスを作成しましょう。
public class App {
    public static void main(String[] args) {
        Integer portNumber = 8080;
        if (args.length != 0) {
            portNumber = Integer.valueOf(args[0]);
        }
        System.out.println("Port number is: " + portNumber);
    }
}
シンプルなコード。入力パラメータを指定してポート値を変更できます。ご覧のとおり、なぜなら Stringパラメータからポート値を読み取り、Integerを介して取得しますInteger.valueOf。したがって、プリミティブ型ではなくオブジェクト型として指定する必要がありますInteger。ここで、一方ではオブジェクト変数があり、デフォルト値はプリミティブです。そしてそれはうまくいきます。でも、私たちは魔法を信じていませんよね?よく言われるように、「ボンネットの下」を見てみましょう。「Download ZIP」をクリックして、compilejava.net からソース コードをダウンロードします。その後、ダウンロードしたアーカイブをディレクトリに解凍し、そこに移動します。ここで、javap -c -p App.classApp.class は、クラスのコンパイル済みクラス ファイルです。次のようなコンテンツが表示されます。
Java でのオートボックス化とアンボックス化 - 2
これは同じ悪名高い「バイトコード」です。しかし、今私たちにとって重要なのは、私たちが見ているものです。まず、8080 プリミティブがメソッド実行スタックに配置され、次にInteger.valueOfが実行されます。これがボクシングの「魔法」です。そして、マジックの内部は次のようになります。
Java でのオートボックス化とアンボックス化 - 3
つまり、本質的には、数値の値に応じて、新しいものが取得されるIntegerか、キャッシュから取得されますInteger(キャッシュは単なる整数の配列にすぎません)。当然のことながら、Integer幸運だったのは一人だけではありません。関連するプリミティブ型とそのラッパー (OOP 世界でプリミティブを表すクラス) の完全なリストがあります。このリストは、Oracle のチュートリアル「Autoboxing and Unboxing」の一番下に記載されています。プリミティブから作成された配列には、サードパーティのライブラリを接続しない限り「ラッパー」がないことにすぐに注意してください。それらの。から私たちのためにArrays.asList作ることはありません。<h2>ボックス化解除</h2>ボックス化の逆のプロセスは、ボックス化解除と呼ばれます。解凍例を見てみましょう。 int[]ListInteger
public class App {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please, enter params");
            return;
        }
      	int value = Math.abs(Integer.valueOf(args[0]));
        System.out.println("Absolute value is: " + value);
    }

}
Math.absプリミティブのみを受け入れます。何をするか?ラッパー クラスには、この場合にプリミティブを返す特別なメソッドがあります。たとえば、これはintValueIntegerメソッドです。バイトコードを見ると次のようになります。
Java でのオートボックス化とアンボックス化 - 4
ご覧のとおり、魔法はありません。すべては Java 内にあります。それは「単独で」機能するだけです。私たちの便宜のため。<h2>熊手</h2>
Java でのオートボックス化とアンボックス化 - 5
どのようなツールも、使い方を誤れば、それ自体に対して恐るべき武器となります。Java の自動ボックス化/ボックス化解除メカニズムも例外ではありません。最初の明らかな比較は、 によるものです==。これは明らかだと思いますが、もう一度見てみましょう。
public static void main(String[] args) {
    Integer inCacheValue = 127;
    Integer inCacheValue2 = 127;
    Integer notInCache = 128; // new Integer(129)
    Integer notInCache2 = 128; // new Integer(129)
    System.out.println(inCacheValue == inCacheValue2); //true
    System.out.println(notInCache == notInCache2); //false
}
最初のケースでは、値はInteger値キャッシュから取得されます (上記のボクシングの説明を参照)。2 番目のケースでは、毎回新しいオブジェクトが作成されます。しかし、ここは予約する価値があります。この動作は、キャッシュの上限 ( java.lang.Integer.IntegerCache.high ) によって異なります。また、この制限は他の設定によって変更される場合があります。stackoverflow でこのトピックに関するディスカッションを読むことができます: How size the Integer Cache? 当然のことながら、オブジェクトは等しいものを使用して比較する必要があります。 System.out.println(notInCache.equals(notInCache2)); 同じメカニズムに関連する 2 番目の問題はパフォーマンスです。Java におけるボックス化は、新しいオブジェクトを作成することと同じです。数値がキャッシュ値に含まれていない場合 (つまり、-128 ~ 127)、毎回新しいオブジェクトが作成されます。突然パッケージング (ボックス化) がループ内で実行されると、不要なオブジェクトが大幅に増加し、ガベージ コレクターの作業のためのリソースが消費されます。したがって、あまり無謀に考えないでください。3 番目の、同様に痛みを伴う熊手は、同じメカニズムから生じます。
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
このコードでは、その人は明らかにエラーを回避しようとしていました。しかし、 のチェックはありませんnull。それが入力に関してはnull、理解できるエラーではなく、理解できないエラーが返されますNullPointerException。比較のために、Java は実行しようとしてvalue.intValueクラッシュするためです。value意思null。<h2>結論</h2>ボックス化/アンボックス化メカニズムを使用すると、プログラマは作成するコードの量が減り、場合によってはプリミティブからオブジェクトへの変換、またはその逆の変換について考える必要さえなくなります。しかし、それはその仕組みを忘れるべきだという意味ではありません。そうしないと、すぐには現れない間違いを犯す可能性があります。私たちが完全に制御できないシステムの部分 (整数境界など) に依存すべきではありません。ただし、ラッパー クラス ( など) のすべての利点を忘れないでくださいInteger。多くの場合、これらのラッパー クラスには、作業を改善し、コードの表現力を高める追加の静的メソッドのセットが含まれています。以下にキャッチアップの例を示します。
public static void main(String[] args) {
    int first = 1;
    int second = 5;
    System.out.println(Integer.max(first, second));
    System.out.println(Character.toLowerCase('S'));
}
すべてから見て正しい結論は、魔法など存在しない、ある種の認識があるということです。そして、すべてが常に期待通りになるわけではありません。たとえば、パッケージ化はありません。 System.out.println("The number is " + 8); 上記の例は、コンパイラによって 1 行に最適化されます。つまり、「数字は8」と書いたようなものです。また、以下の例では、パッケージ化も行われません。
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
printlnオブジェクトを入力として受け取り、何らかの方法で線を接続する必要がある 場合はどうなるでしょうか。ライン... はい、そのためパッケージ自体はありません。静的メソッドもありますIntegerが、その一部は ですpackage。つまり、私たちはそれらを使用できませんが、Java 自体では積極的に使用できます。ここではまさにこれが当てはまります。getChars メソッドが呼び出され、数値から文字の配列が作成されます。繰り返しますが、魔法はありません。Java だけです)。したがって、状況が不明確な場合でも、実装を確認するだけで、少なくとも何かが適切に配置されます。#ヴィアチェスラフ
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION