Javaで自動ボックス化とボックス化解除を使用するのはなぜですか?


81

オートボクシングは、Javaコンパイラがプリミティブ型とそれに対応するオブジェクトラッパークラスの間で行う自動変換です。たとえば、intを整数に、doubleをDoubleに変換するなどです。変換が逆の場合、これはボックス化解除と呼ばれます。

では、なぜそれが必要なのか、そしてなぜJavaで自動ボックス化とボックス化解除を使用するのでしょうか。


1
基本的にはジェネリック医薬品のための...
nachokk

3
Integer持っているparseInt方法を。int持っていない。:)
Vishal Zanzrukia 2014

@VishalZanzrukiaでは、機能を増やすためだけですか?

12
持つことはできList<Integer>ますが、持つことはできませんList<int>
Vishal Zanzrukia 2014

はい..正確に..より多くの機能を取得するには
Vishal Zanzrukia 2014

回答:


173

この背後にある主な理由を完全に理解するには、いくつかのコンテキストが必要です。

プリミティブとクラス

Javaのプリミティブ変数には、値(整数、倍精度浮動小数点2進数など)が含まれます。これらの値の長さは異なる可能性があるため、それらを含む変数の長さも異なる可能性があります(float対を検討してくださいdouble)。

一方、クラス変数にはインスタンスへの参照含まれています。参照は通常、多くの言語でポインター(またはポインターに非常によく似たもの)として実装されます。これらのことは、一般的にかかわらず、彼らが(参照インスタンスのサイズの、同じ大きさを持っているObjectStringInteger、など)。

クラス変数のこのプロパティは、それらに含まれる参照を(ある程度)交換可能にします。これにより、置換と呼ばれるものを実行できます。大まかに言えば、特定のタイプのインスタンスを別の関連するタイプのインスタンスとして使用できます(たとえば、をStringとして使用Objectします)。

プリミティブ変数は、相互に、またはObject。と同じように交換可能はありません。これの最も明白な理由(しかし唯一の理由ではありません)はそれらのサイズの違いです。これにより、プリミティブ型はこの点で不便になりますが、それでも言語で必要です(主にパフォーマンスに帰着する理由のため)。

ジェネリックスと型消去

ジェネリック型は、1つ以上の型パラメーターを持つ型です(正確な数はジェネリックアリティと呼ばれます)。たとえば、ジェネリック型定義 List<T>には型パラメーターTがあり、(具象型をObject生成する)、()、()などになります。 List<Object>StringList<String>IntegerList<Integer>

ジェネリック型は、非ジェネリック型よりもはるかに複雑です。彼らは、Java(最初のリリース後)に導入されたとき、JVMへの根本的な変更を行うと、おそらく古いバイナリとの互換性を壊さないようにするために、ジャワの作成者は、少なくとも侵襲的な方法でジェネリック型を実装することを決めた:すべての具体的な種類をList<T>実際には、(のバイナリに相当する)にコンパイルされます(List<Object>他のタイプの場合、境界は以外のものになる可能性Objectがありますが、要点はわかります)。このプロセスでは、一般的なアリティと型パラメータの情報が失われるため型消去と呼びます。

2つをまとめる

ここで問題は、上記の現実の組み合わせです。 List<T>List<Object>すべての場合にになる場合は、T常にに直接割り当てることができるタイプである必要がありますObject。それ以外は許可されません。、私たちは前に言ったように、以来intfloatおよびdoubleと互換性がありませんObject、そこにすることはできませんList<int>List<float>またはList<double>(ジェネリック医薬品のかなり多くの複雑な実装がJVMに存在していない限り)。

しかし、Javaは次のようなタイプを提供します IntegerFloatそしてDoubleどのようにそれらを効果的に置換すること、クラスのインスタンスでこれらのプリミティブを包むObjectように、プリミティブとの間接的な作業にジェネリック型を許可する(あなたがいるためにもすることができます持ってList<Integer>List<Float>List<Double>など)。

作成のプロセスIntegerからintFloatよりfloatようにとは、呼び出されボクシング。その逆は開封と呼ばれます。プリミティブを使用するたびにボックス化する必要があるのObjectは不便なので、言語がこれを自動的に行う場合があります-と呼ばれていますオートボクシングが


あなたの説明によると、ジェネリックスを実装するには、これらのクラスInteger、String、...が必要です。他に理由はありますか?
BishwasMishra20年

1
@BishwasMishraこれらの値をObjectインスタンスとして使用できるように、これらがあります。型消去によるジェネリックスは、その1つのアプリケーションです。
TheodorosChatzigiannakis20年

16

自動ボクシングは、プリミティブデータ型をラッパークラスオブジェクトに変換するために使用されます。ラッパークラスは、プリミティブ型で実行されるさまざまな機能を提供します。最も一般的な例は次のとおりです。

int a = 56;
Integer i = a; // Auto Boxing

それはされて必要なコードを直接記述すると、JVMはボクシングとアンボクシングの世話をすることができるように簡単なので、プログラマの。

自動ボクシングは、java.util.Collectionタイプを操作するときにも役立ちます。プリミティブ型のコレクションを作成する場合、プリミティブ型のコレクションを直接作成することはできません。オブジェクトのコレクションのみを作成できます。例えば ​​:

ArrayList<int> al = new ArrayList<int>(); // not supported 

ArrayList<Integer> al = new ArrayList<Integer>(); // supported 
al.add(45); //auto Boxing 

ラッパークラス

Javaの8つのプリミティブ型(byte、short、int、float、char、double、boolean、long)のそれぞれには、それらに関連付けられた個別のWrapperクラスがあります。これらのWrapperクラスには、プリミティブデータ型で有用な操作を実行するための事前定義されたメソッドがあります。

ラッパークラスの使用

String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.

Wrapperクラスが提供する便利な関数はたくさんあります。Javaドキュメントをチェックしてくださいここで

Unboxingは、ラッパークラスオブジェクトをプリミティブ型に変換するAutoBoxingの反対です。これはJVMによって自動的に行われるため、特定の操作にラッパークラスを使用し、プリミティブが処理を高速化するため、それらをプリミティブ型に変換し直すことができます。例えば ​​:

Integer s = 45;
int a = s; auto UnBoxing;

オブジェクトを処理するコレクションの場合、自動ボックス化解除のみが使用されます。方法は次のとおりです。

ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 

4

プリミティブ(非オブジェクト)タイプには、効率に正当性があります。

プリミティブ型int, boolean, doubleは即時データですが、Objectsは参照です。したがって、フィールド(または変数)

int i;
double x;
Object s;

ローカルメモリ4+ 8 + 8が必要ですか?ここで、オブジェクトの場合、メモリへの参照(アドレス)のみが格納されます。

オブジェクトラッパーInteger, Doubleなどを使用すると、ヒープメモリ内の整数/倍精度インスタンスへの間接参照を導入できます。

なぜボクシングが必要なのですか?

それは相対的な範囲の問題です。将来のJavaではArrayList<int>、リフティングプリミティブ型を使用できるようになる予定です。

回答:今のところ、ArrayListはオブジェクトに対してのみ機能し、オブジェクト参照用のスペースを予約し、同様にガベージコレクションを管理します。したがって、ジェネリック型はオブジェクトの子です。したがって、浮動小数点値のArrayListが必要な場合は、doubleをDoubleオブジェクトでラップする必要がありました。

ここで、Javaは、テンプレートが従来のC ++とは異なります。C++クラス vector<string>, vector<int>は2つのコンパイル製品を作成します。Javaの設計では、すべてのパラメータータイプに新しいコンパイル済み製品を必要とせずに、1つのArrayList.classを使用するようになりました。

したがって、オブジェクトにボックス化しないと、パラメータタイプが出現するたびにクラスをコンパイルする必要があります。具体的には、すべてのコレクションまたはコンテナクラスには、Object、int、double、booleanのバージョンが必要です。Objectのバージョンは、すべての子クラスを処理します。

実際、このような多様化の必要性は、int、char、doubleで動作するIntBuffer、CharBuffer、DoubleBufferなどのJavaSEにすでに存在していました。これらのソースを一般的なソースから生成することで、ハッキーな方法で解決されました。


4

JDK 5以降、javaには自動ボクシングと自動アンボックスの2つの重要な機能が追加されました。AutoBoxingは、そのようなオブジェクトが必要になるたびに、プリミティブ型が同等のラッパーに自動的にカプセル化されるプロセスです。オブジェクトを明示的に作成する必要はありません。自動ボックス化解除は、カプセル化されたオブジェクトの値が必要なときに型ラッパーから自動的に抽出されるプロセスです。intValue()doubleValue()などのメソッドを呼び出す必要はありません。

自動ボックスと自動ボックス解除の追加により、アルゴリズムの記述が大幅に簡素化され、値の手動でのボックス化とボックス化解除の餌がなくなります。間違い避けることも役立ちます。また、オブジェクトのみを操作するジェネリックにとっても非常に重要です。最後に、オートボクシングはコレクションフレームワークでの作業を容易にします


2

なぜ(開封)ボクシングがあるのですか?

プリミティブとそのオブジェクト指向(OO)の代替を混合するコードの記述を、より快適で冗長性の低いものにするため。

なぜプリミティブとそのOOの選択肢があるのですか?

プリミティブ型は(C#とは異なり)クラスではないため、のサブクラスではありません Objectはなく、オーバーライドすることはできません。

intパフォーマンス上の理由からのようなプリミティブと、オブジェクト指向プログラミングの利点のためのObjectような代替手段がIntegerあり、マイナーな点として、ユーティリティ定数とメソッド(Integer.MAX_VALUEおよびInteger.toString(int))の適切な場所があります。

OOの利点は、Generics(List<Integer>)で最も簡単に確認できますが、これに限定されません。たとえば、次のようになります。

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}

1

一部のデータ構造はオブジェクトのみを受け入れることができ、プリミティブ型は受け入れません。

例:HashMapのキー。

詳細については、この質問を参照してください:キーとしてのHashMapとint

データベースの「int」フィールドなど、他にも正当な理由がありますが、これもNULLになる可能性があります。Javaのintをnullにすることはできません。整数参照はできます。自動ボックス化とボックス化解除は、変換の前後に無関係なコードを記述しないようにする機能を提供します。


0

種類が違うので、便利です。パフォーマンスがプリミティブ型を持つ理由である可能性があります。


0

ArrayListはプリミティブ型をサポートせず、クラスのみをサポートします。ただし、int、doubleなどのプリミティブ型を使用する必要があります。

ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted.

ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.

Integerクラスは、プリミティブ型intの値をオブジェクトにラップします。したがって、次のコードが受け入れられます。

ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.

add(value)メソッドで値を追加できます。文字列値を追加するには、strArrayListコードで「Hello」と言ってください。

strArrayList.add("Hello");  

そして、int値を追加して54と言います。

intArrayList.add(54);

しかし、intArrayList.add(54);を書くとき。コンパイラは次の行に変換します

intArrayList.add(Integer.valueOf(54)); 

intArrayList.add(54)はユーザー側から簡単で受け入れやすいので、コンパイラーは `という難しい仕事をします。intArrayList.add(Integer.valueOf(54)); autoBoxingます。

同様に、値を取得するには、intArrayList.get(0)と入力するだけで、コンパイラ<code>intArrayList.get(0).intValue();はautoUnboxingに変換します。


0

オートボクシング:プリミティブ値を対応するラッパークラスのオブジェクトに変換します。

ボックス化解除:ラッパータイプのオブジェクトを対応するプリミティブ値に変換します

// Java program to illustrate the concept 
// of Autoboxing and Unboxing 
import java.io.*; 

class GFG 
{ 
    public static void main (String[] args) 
    { 
        // creating an Integer Object 
        // with value 10. 
        Integer i = new Integer(10); 

        // unboxing the Object 
        int i1 = i; 

        System.out.println("Value of i: " + i); 
        System.out.println("Value of i1: " + i1); 

        //Autoboxing of char 
        Character gfg = 'a'; 

        // Auto-unboxing of Character 
        char ch = gfg; 
        System.out.println("Value of ch: " + ch); 
        System.out.println("Value of gfg: " + gfg); 

    } 
} 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.