Javaコレクションがプリミティブ型を直接格納できないのはなぜですか?


123

Javaコレクションは、プリミティブ型ではなくオブジェクトのみを格納します。ただし、ラッパークラスを格納できます。

なぜこの制約なのか?


2
この制約は、プリミティブを処理していて、キューを使用して送信する場合、送信速度が非常に高速である場合には不十分です。私は今、オートボクシングの時間がかかりすぎるという問題に対処しています。
JPM

技術的には、プリミティブ型はオブジェクト(正確にはそのようなシングルトンインスタンス)でありclass、JVMではなくによって定義されるだけではありません。ステートメントint i = 1int、JVMで1定義されている値に設定された、JVM で定義されているオブジェクトのシングルトンインスタンスへのポインターを定義します。はい、Javaのポインター-これは、言語の実装によって抽象化されています。総称としてプリミティブを使用することはできません。言語はすべての総称型がスーパータイプでなければならないことを述語しているため、実行時にコンパイルされるObject理由です。A<?>A<Object>
Robert E Fry

1
@RobertEFryプリミティブ型はJavaのオブジェクトではない ため、シングルトンインスタンスなどについて記述したものはすべて根本的に間違っており、混乱を招きます。オブジェクトとは何かを定義しているJava言語仕様の「タイプ、値、変数」の章を読むことをお勧めします。 」
タイプレーサー

回答:


99

これはJavaの設計上の決定であり、間違いと考える人もいます。コンテナーはオブジェクトを必要とし、プリミティブはオブジェクトから派生しません。

これは、.NET設計者がJVMから学び、多くの場合ボクシングが排除されるように値タイプとジェネリックを実装した1つの場所です。CLRでは、汎用コンテナーは、基になるコンテナー構造の一部として値型を格納できます。

Javaは、JVMからのサポートなしで、コンパイラーに汎用サポートを100%追加することを選択しました。JVMとは、「非オブジェクト」オブジェクトをサポートしていません。Javaジェネリックを使用すると、ラッパーがないように見せかけることができますが、ボクシングのパフォーマンスは犠牲になります。これは、特定のクラスのプログラムにとって重要です。

ボクシングは技術的な妥協であり、実装の詳細が言語に漏れていると感じています。オートボクシングは優れた構文上の砂糖ですが、それでもパフォーマンスが低下します。どちらかといえば、自動ボックス化するときにコンパイラーに警告を出してほしい。(私が知っているすべてのために、それは今かもしれません、私は2010年にこの回答を書きました)。

ボクシングに関するSOの良い説明:なぜ一部の言語ではボクシングとアンボクシングが必要なのですか?

Javaジェネリックに対する批判:ジェネリックの Javaの実装が悪いと主張する人がいるのはなぜですか?

Javaの防御では、後ろを向いて批判することは簡単です。JVMは時の試練に耐え、多くの点で優れた設計です。


6
間違いではなく、慎重に選択されたトレードオフがJavaに実際に役立ったと私は信じています。
DJClayworth

13
.NETがそれから学び、最初からオートボクシングを実装し、ボクシングのオーバーヘッドなしにVMレベルでジェネリックスを実装したのは、十分な間違いでした。Java自身による修正の試みは構文レベルのソリューションにすぎず、オートボクシングのパフォーマンスへの影響と、ボクシングの影響はまったく受けていません。Javaの実装では、データ構造が大きいとパフォーマンスが低下します。
codenheim、2011年

2
@mrjoltcola:IMHO、デフォルトのオートボクシングは間違いですが、変数とパラメーターにタグを付ける方法があり、それらに与えられた値を自動的にボックス化する必要がありました。今でも、特定の変数またはパラメーターが新しくオートボックス化された値を受け入れないように指定する手段が追加されるべきだと思います[ ボックス化された整数を識別するObject.ReferenceEquals型の参照を渡すことは正当であるはずですがObject、整数値を渡します]。Javaの自動unboxingは、私見では厄介です。
スーパーキャット2014年

18

実装が簡単になります。Javaプリミティブはオブジェクトとは見なされないため、これらのプリミティブごとに個別のコレクションクラスを作成する必要があります(共有するテンプレートコードはありません)。

もちろん、そうすることができます。GNUTroveApache Commons Primitives、またはHPPCを参照してください。

本当に大きなコレクションがない限り、ラッパーのオーバーヘッドは人々が気にするのに十分問題ではありません(そして本当に大きなプリミティブコレクションがある場合、それらのために特別なデータ構造の使用/構築を調べることに労力を費やすこともできます) )。


11

これは2つの事実の組み合わせです。

  • Javaプリミティブ型は参照型でintはありません(例:はでないObject
  • Javaは参照型の型消去を使用してジェネリックスを実行します(たとえば、List<?>実際にはa List<Object>は実行時です)

これらの両方が真であるため、ジェネリックJavaコレクションはプリミティブ型を直接格納できません。便宜上、プリミティブ型を参照型として自動的にボックス化できるようにオートボクシングが導入されています。それについては間違いありませんが、コレクションは依然としてオブジェクト参照を保存しています。

これは回避できたでしょうか?たぶん。

  • もし intObject、すべてのボックスタイプのための必要はありません。
  • ジェネリックが型消去を使用して行われていない場合、プリミティブが型パラメーターに使用されている可能性があります。

8

自動ボックス化と自動ボックス化解除の概念があります。をJava に保存しようとintするとList<Integer>、Javaコンパイラによって自動的にに変換されますInteger


1
AutoboxingはGenericsとともにJava 1.5で導入されました。
ジェレミー

1
しかし、それはコンパイル時のものです。パフォーマンス上の利点のない構文糖。Javaコンパイラーはオートボックス化されるため、ジェネリックである.NETのようなVM実装と比較して、パフォーマンスが低下します。ボクシングは含まれません。
codenheim、2011年

1
@mrjoltcola:あなたのポイントは何ですか?事実を共有するだけで、議論はしませんでした。
Jeremy

3
構文とパフォーマンスの違いを指摘することが重要です。また、コメントではなく、事実の共有を検討しています。ありがとう。
codenheim、2011年

2

それは本当に制約ではありませんか?

プリミティブ値を格納するコレクションを作成するかどうかを検討してください。int、float、charのいずれかを格納できるコレクションをどのように記述しますか?ほとんどの場合、複数のコレクションが作成されるため、intlistやcharlistなどが必要になります。

コレクションクラスを記述するときにJavaのオブジェクト指向の性質を利用すると、任意のオブジェクトを格納できるため、必要なコレクションクラスは1つだけです。この多態性という考え方は非常に強力で、ライブラリの設計を大幅に簡素化します。


7
「int、float、charのいずれかを格納できるコレクションをどのように作成しますか?」-他の言語のように適切に実装されたジェネリックス/テンプレートを使用すると、すべてのものを偽装するというペナルティを支払う必要がありません。
codenheim、2010年

Javaの6年間で、プリミティブのコレクションを保存したいと思ったことはほとんどありません。参照オブジェクトを使用するための余分な時間とスペースのコストを必要とする可能性があったいくつかのケースでさえ、ごくわずかです。特に、私は多くの人がMap <int、T>が欲しいと思っていることに気づき、配列はそのトリックを非常にうまく行うことを忘れています。
DJClayworth、2011年

2
@DJClayworthこれは、キー値が非スパースの場合にのみ機能します。もちろん、補助配列を使用してキーを追跡することもできますが、それ自体に問題があります。比較的効率的なアクセスでは、キーの順序に基づいて両方の配列をソートしてバイナリ検索を可能にし、挿入と削除を行う必要があります。挿入/削除が以前に削除されたアイテムがあった場所で終了する可能性が高いように挿入/削除がパターン化されていない、および/またはいくつかのバッファが配列などに散在している場合を除いて、非効率的です。利用可能なリソースがありますが、 Java自体。
JAB

@JAB実際には、キーがスパースの場合は問題なく機能します。スパースでない場合よりも多くのメモリが必要です。そして、それらのキーがスパースである場合、それらのキーが多くなく、キーとしてIntegerを使用しても問題ないことを意味します。必要なメモリが最も少ない方法を使用します。または、気にしない場合はどちらでもかまいません。
DJクレイワース2014年

0

私は、おそらくこのJEP(http://openjdk.java.net/jeps/218)に基づいて、Java 10のJDKのこの領域で進展が見られると思います。

今日のコレクションでプリミティブをボックス化することを避けたい場合は、サードパーティの代替手段がいくつかあります。前述のサードパーティオプションに加えて、EclipseコレクションFastUtil、およびKolobokeもあります。

プリミティブマップの比較も、先ほどタイトルとともに公開されました:ラージHashMapの概要:JDK、FastUtil、Goldman Sachs、HPPC、Koloboke、Trove。GSコレクション(ゴールドマンサックス)ライブラリはEclipse Foundationに移行され、現在はEclipseコレクションになっています。


0

主な理由は、Javaの設計戦略です。++ 1)コレクションは操作のためにオブジェクトを必要とし、プリミティブはオブジェクトから派生していないため、これは別の理由である可能性があります。2)Javaプリミティブデータ型はexの参照型ではありません。intはオブジェクトではありません。

克服するために:-

自動ボクシングと自動アンボクシングの概念があります。そのため、プリミティブデータ型を保存しようとすると、コンパイラはそれを自動的にそのプリミティブデータクラスのオブジェクトに変換します。

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