web-dev-qa-db-ja.com

なぜJava APIはshortまたはbyteの代わりにintを使用しますか?

intまたはshortで十分な場合、Java APIはbyteを使用するのはなぜですか?

例: DAY_OF_WEEK クラスのフィールド Calendarintを使用します。

差が非常に小さい場合、それらのデータ型(shortint)がまったく存在しないのはなぜですか?

134
Willi Mentzel

(ほぼ)byteshortのすべての操作は、それらをintに昇格させます。たとえば、次のように書くことはできません。

_short x = 1;
short y = 2;

short z = x + y; //error
_

intを使用する場合、算術演算は簡単で簡単です。キャストする必要はありません。

スペースに関しては、非常に少し違います。 byteshortは事態を複雑にしますが、一定量の変数について話しているので、このマイクロ最適化は価値があるとは思いません。

byteは、組み込みデバイス用にプログラムする場合、またはファイル/ネットワークを扱う場合に関連し、有用です。また、これらのプリミティブは制限されていますが、将来計算が制限を超える可能性がある場合はどうなりますか?より大きな数に進化する可能性のあるCalendarクラスの拡張について考えてみてください。

また、64ビットプロセッサでは、ローカルはレジスタに保存され、リソースを使用しないため、intshortおよびその他のプリミティブを使用してもまったく違いはありません。 。さらに、多くのJava実装は変数を整列します* (およびオブジェクト)。


* byteおよびshortは、ローカル変数、クラス変数、または偶数である場合、intと同じスペースを占有しますインスタンス変数。どうして? (ほとんどの)コンピューターシステムでは、変数のアドレスはalignedであるため、たとえば1バイトを使用すると、実際には2バイトになります-1つは変数自体用で、もう1つはパディング用です。

一方、配列では、byteが1バイト、shortが2バイト、intが4バイトを使用します。これは、配列では開始と終了のみであるためです。整列する必要があります。これは、たとえばSystem.arraycopy()を使用したい場合に違いを生み、パフォーマンスの違いに本当に気付くでしょう。

39
Maroun

整数を使用すると、短整数型に比べて算術演算が簡単だからです。定数が実際にshort値によってモデル化されたと仮定します。次に、この方法でAPIを使用する必要があります。

short month = Calendar.JUNE;
month = month + (short) 1; // is july

明示的なキャストに注意してください。短値は、算術演算で使用される場合、int値に暗黙的に昇格されます。 (オペランドスタックでは、shortsはintとしても表現されます。)これは使用するのが非常に面倒であり、定数にint値がしばしば好まれます。

それに比べて、このような定数は一定数しか存在しないため、ストレージ効率の向上はわずかです。 40個の定数について話しています。ストレージをintからshortに変更すると安全です40 * 16 bit = 80 byte。詳細については、 この回答 を参照してください。

7

整数定数が収まる最小の型に格納されるという哲学を使用した場合、Javaには深刻な問題が発生します。定数の型が重要かどうかをチェックするコードに追加し、そうであればドキュメントで型を検索し、必要な型変換を実行します。

深刻な問題の概要を説明したので、その哲学でどのようなメリットを達成できますか?その変更のonly runtime-observable効果が、リフレクションを介して定数を調べたときにどのタイプになるかは、驚くことではありません。 (そしてもちろん、定数の型を正しく考慮していない怠laな/意図しないプログラマーによって導入されたエラーはすべて)

長所と短所を比較検討するのは非常に簡単です。それは悪い哲学です。

5
Hurkyl

仮想マシンの設計の複雑さは、実行できる操作の種類の関数です。 「乗算」のような命令の4つの実装(32ビット整数、64ビット整数、32ビット浮動小数点、および64ビット浮動小数点にそれぞれ1つ)を持たせることは、さらに、上記に加えて、より小さい数値型のバージョンも同様です。より興味深い設計上の質問は、64個の整数ですべての整数計算を実行する、および/または64ビットの浮動小数点値ですべての浮動小数点計算を実行する、4つではなく4つの型が必要な理由です。 32ビット整数を使用する理由は、Javaは16ビットまたは8ビットタイプと同じくらい迅速に32ビットタイプを処理できる多くのプラットフォームで実行されることが期待されていましたが、 64ビットタイプの操作は著しく遅くなります。16ビットタイプの処理が高速になるプラットフォームでも、32ビットの量を処理する追加コストは、only32ビットタイプ。

32ビット値で浮動小数点計算を実行する場合、利点は少し明確ではありません。すべてのオペランドをより高精度の型に変換し、それらを追加してから、結果をストレージ用の32ビット浮動小数点数に戻すことにより、float a=b+c+d;のような計算を最も迅速に実行できるプラットフォームがいくつかあります。 32ビット浮動小数点値を使用してすべての計算を実行する方が効率的なプラットフォームは他にもあります。 Javaの作成者は、すべてのプラットフォームが同じように物事を行う必要があり、32ビット浮動小数点計算がより長いハードウェアプラットフォームよりも速いハードウェアプラットフォームを優先することを決定しました。これにより、通常のPCと、浮動小数点ユニットのない多くのマシンで、浮動小数点演算の速度と精度の両方が大幅に低下しますが、btw、b、c、dの値によっては、前述のfloat a=b+c+d;のような式を計算するときに高精度の中間計算を使用すると、すべての中間オペランドがfloat精度で計算された場合よりもはるかに正確な結果が得られる場合がありますが、いずれにせよ、サンはすべてを同じ方法で行うべきであると判断し、最小精度のfloat値を使用することを選択しました。

小さいデータ型の主な利点は、大量のデータ型が配列に一緒に格納されるときに明らかになることに注意してください。 64ビットより小さい型の個々の変数を使用する利点がなくても、小さな値をよりコンパクトに格納できる配列を用意することは価値があります。ローカル変数をbyteではなくlongにすると、7バイト節約できます。 1,000,000個の数字の配列を持つと、各数字はbyte波ではなくlongとして7,000,000バイト保持されます。各配列タイプは少数の操作(特に1つのアイテムの読み取り、1つのアイテムの保存、配列内のアイテムの範囲のコピー、ある配列から別の配列へのアイテムの範囲のコピー)のみをサポートする必要があるため、配列タイプは、より多くのタイプの直接使用可能な離散数値を持つ複雑さほど深刻ではありません。

4
supercat

実際、小さな利点があります。あなたが持っている場合

_class MyTimeAndDayOfWeek {
    byte dayOfWeek;
    byte hour;
    byte minute;
    byte second;
}
_

次に、典型的なJVMでは、単一のintを含むクラスと同じくらいのスペースが必要です。メモリ消費は、8または16バイトの次の倍数(IIRC、構成可能)に丸められるため、実際に保存されるケースはかなりまれです。

このクラスは、対応するCalendarメソッドがbyteを返した場合、少し使いやすくなります。しかし、そのようなCalendarメソッドはなく、他のフィールドのためにintを返す必要があるget(int)のみがあります。小さい型の各操作はintに昇格するため、多くのキャストが必要です。

おそらく、あなたはあきらめてintに切り替えるか、次のようなセッターを書くでしょう。

_void setDayOfWeek(int dayOfWeek) {
    this.dayOfWeek = checkedCastToByte(dayOfWeek);
}
_

とにかく、_DAY_OF_WEEK_のタイプは関係ありません。

2
maaartinus