Javaのプリミティブ型short
について質問があります。 JDK 1.6を使用しています。
次のものがある場合:
short a = 2;
short b = 3;
short c = a + b;
コンパイラはコンパイルしたくない-それは「intからshortに変換できない」と言い、short
にキャストすることを提案します。
short c = (short) (a + b);
本当に機能します。しかし、私の質問は、なぜキャストする必要があるのですか? aとbの値はshort
の範囲にあります-短い値の範囲は{-32,768、32767}です。また、操作を実行するときにキャストする必要があります-、*、/(他のチェックはしていません)。
プリミティブ型int
に対して同じことをすれば、aa + bbをint
にキャストする必要はありません。以下が正常に機能します。
int aa = 2;
int bb = 3;
int cc = aa +bb;
Short型の2つの変数を追加する必要があるクラスを設計しているときにこれを発見し、コンパイラはキャストを作成することを望んでいました。 int
型の2つの変数を使用してこれを行う場合、キャストする必要はありません。
ちょっとした注意:プリミティブ型byte
でも同じことが起こります。したがって、これは機能します:
byte a = 2;
byte b = 3;
byte c = (byte) (a + b);
しかし、これはそうではありません:
byte a = 2;
byte b = 3;
byte c = a + b;
long
、float
、double
、およびint
の場合、キャストする必要はありません。 short
およびbyte
の値のみ。
short C# で説明されているように(ただし、Javaのような他の言語コンパイラも同様)
Shortからint、long、float、double、またはdecimalへの暗黙的な変換が事前に定義されています。
大きなストレージサイズの非リテラル数値型を暗黙的にshort型に変換することはできません(整数型のストレージサイズについては、「整数型の表」を参照してください)。たとえば、次の2つの短い変数xとyを考えます。
short x = 5, y = 12;
次の代入ステートメントは、代入演算子の右側の算術式がデフォルトでintに評価されるため、コンパイルエラーを生成します。
short z = x + y; // Error: no conversion from int to short
この問題を修正するには、キャストを使用します。
short z = (short)(x + y); // OK: explicit conversion
ただし、次のステートメントを使用することもできます。この場合、宛先変数は同じストレージサイズまたはより大きなストレージサイズを持ちます。
int m = x + y;
long n = x + y;
良いフォローアップの質問は:
「代入演算子の右側の算術式がデフォルトでintに評価される理由」
最初の回答は次の場所にあります。
Java言語仕様は、整数の表現方法と整数算術式の評価方法を正確に定義しています。これはJavaの重要なプロパティです。このプログラミング言語はインターネット上の分散アプリケーションで使用するように設計されているためです。A Javaプログラムは、それを実行するターゲットマシンとは無関係に同じ結果を生成する必要があります。
対照的に、C(および広く使用されている命令型およびオブジェクト指向プログラミング言語の大部分)はより粗雑であり、多くの重要な特性を残しています。この不正確な言語仕様の背後にある意図は明確です。同じCプログラムは、ターゲットプロセッサに組み込まれた算術演算を使用してソースプログラムの整数演算をインスタンス化することにより、16ビット、32ビット、または64ビットのアーキテクチャで実行されることになっています。これにより、利用可能なマシン操作を直接使用できるため、コードの効率が大幅に向上します。整数計算が「十分に小さい」数値のみを処理する限り、矛盾は発生しません。
この意味で、C整数演算は、プログラミング言語仕様によって正確に定義されていないプレースホルダーであり、ターゲットマシンを決定することによってのみ完全にインスタンス化されます。
Javaは、整数の表現方法と整数演算の計算方法を正確に定義します。
Java Integers
--------------------------
Signed | Unsigned
--------------------------
long (64-bit) |
int (32-bit) |
short (16-bit) | char (16-bit)
byte (8-bit) |
Charは唯一の符号なし整数型です。その値は、
\u0000
から\uffff
のUnicode文字を表します。つまり、0から2です。16-1。整数演算子にlong型のオペランドがある場合、もう一方のオペランドもlong型に変換されます。それ以外の場合、必要に応じて短いオペランドがintに変換される場合、int型のオペランドに対して演算が実行されます。変換規則は正確に指定されています。
[理論的計算機科学の電子ノートから82 No. 2(2003)
Blesner-Blech-COCV 2003: Sabine GLESNER 、Jan Olaf BLECH、
FakultätfürInformatik、
カールスルーエ大学
カールスルーエ、ドイツ]
編集:さて、今ではJavaであることがわかりました...
Java言語仕様 のセクション4.2.2の状態:
Javaプログラミング言語は、整数値に作用するいくつかの演算子を提供します。
[...]
- Intまたはlong型の値をもたらす数値演算子:
- [...]
- 加算演算子+および-(§15.18)
つまり、C#のようなものです-加算演算子(整数型に適用される場合)はint
またはlong
になります。これが、short
変数。
元の回答(C#)
C#では(言語を指定していないので、推測しています)、プリミティブ型の唯一の加算演算子は次のとおりです。
_int operator +(int x, int y);
uint operator +(uint x, uint y);
long operator +(long x, long y);
ulong operator +(ulong x, ulong y);
float operator +(float x, float y);
double operator +(double x, double y);
_
これらは、C#3.0仕様のセクション7.7.4にあります。さらに、10進数の加算が定義されています:
_decimal operator +(decimal x, decimal y);
_
(列挙の追加、文字列の連結、デリゲートの組み合わせもそこで定義されています。)
ご覧のとおり、short operator +(short x, short y)
演算子はありません。したがって、両方のオペランドが暗黙的にintに変換され、int形式が使用されます。つまり、結果は「int」型の式であるため、キャストする必要があります。
C#およびJavaでは、割り当ての右側の算術式はデフォルトでintに評価されます。明らかな理由で、intへの暗黙的な変換形式がないため、shortにキャストバックする必要があるのはそのためです。
「デフォルトでなぜint」という質問に答えられていないことを考えると...
まず、「デフォルト」は正しい用語ではありません(ただし、十分に近い)。 VonCで述べたように、intとlongで構成される式の結果は長くなります。そして、ints/logsとdoublesで構成される操作は、doubleの結果になります。コンパイラーは、式の条件を、結果の範囲や精度が向上する型にプロモートします(浮動小数点型は、整数よりも範囲と精度が高いと推定されますが、大きなlongをdoubleに変換する精度は失われます)。
1つの注意点は、このプロモーションはそれを必要とする用語に対してのみ行われるということです。そのため、次の例では、式全体にdoubleが含まれている場合でも、部分式5/4は整数値のみを使用し、整数演算を使用して実行されます。結果はあなたが期待するものではありません...
(5/4) * 1000.0
では、なぜbyteとshortがintに昇格されるのですか?バックアップするための参照がなければ、それは実用性によるものです。バイトコードの数は限られています。
「バイトコード」は、その名前が示すとおり、1バイトを使用して操作を指定します。たとえば、2つの整数を追加するiadd。現在、 205個のオペコードが定義されています であり、整数演算は 18 を各タイプ(つまり、整数とlongの間で合計36個)に取り、変換演算子はカウントしません。
短く、バイトごとに独自のオペコードセットがある場合、241になり、JVMの拡張機能が制限されます。私が言ったように、これについて私を裏付ける言及はありませんが、ゴスリングらが「どれくらいの頻度で実際にショーツを使用するのか」と言ったのではないかと思います。一方、byteをintにプロモートすると、それほど驚くべき効果は得られません(予想される回答は96、実際の回答は-16です)。
byte x = (byte)0xC0;
System.out.println(x >> 2);
どの言語を使用していますか?
多くのCベースの言語には、任意の数式がサイズint以上で実行されるというルールがあります。このため、2つのshortを追加すると、結果はint型になります。これにより、キャストが必要になります。
Javaは、常に少なくとも32ビット値を計算に使用します。これは、1995年にJavaが導入されたときに一般的だった32ビットアーキテクチャによるものです。CPUのレジスタサイズは32ビットであり、算術論理ユニットはCPUの長さの2したがって、CPUはそのような値に対して最適化されました。
これが、算術演算をサポートし、32ビット未満のすべてのデータ型が、計算に使用するとすぐにint(32ビット)に変換される理由です。
要約すると、これは主にパフォーマンスの問題によるものであり、今日では互換性のために保持されています。
Javaでは、次のようなすべての数値式
anyPrimitive zas = 1;
anyPrimitive bar = 3;
?? x = zas + bar
xは常に少なくともintになるか、追加要素の1つがlongの場合はlongになります。
しかし、いくつかのタフな癖があります
byte a = 1; // 1 is an int, but it won't compile if you use a variable
a += 2; // the shortcut works even when 2 is an int
a++; // the post and pre increment operator work
AFAIS、そのためのfinal
の使用法については誰も言及していません。最後の例を変更し、変数aおよびbをfinal
変数として定義すると、コンパイラーはassuredであり、それらの合計値5は、精度を損なうことなくbyte
型の変数に割り当てることができます。この場合、コンパイラはaとbの合計をcに割り当てるとよいでしょう。変更されたコードは次のとおりです。
final byte a = 2;
final byte b = 3;
byte c = a + b;
「ブール値を除く」「int」より小さいデータ型は、暗黙的に「int」に変換されます。
あなたの場合:
short a = 2;
short b = 3;
short c = a + b;
(a + b)の結果は暗黙的にintに変換されます。そして今、あなたはそれを「short」に割り当てています。それであなたはエラーを得ています。
short、byte、char-これらすべてについて、同じエラーが発生します。
指摘されていないものを追加したいと思います。 Javaは、変数(2および3)に指定した値を考慮しません...
ショートa = 2; short b = 3; short c = a + b;
Javaが知っている限り、これを行うことができます...
ショートa = 32767; short b = 32767; short c = a + b;
これはshortの範囲外になります。結果がshortを超えるがint以下になる可能性があるため、結果をintに自動ボックス化します。基本的にほとんどの人が2,147,483,647を超える値または-2,147,483,648を下回る値をハードコーディングしないため、Intが「デフォルト」として選択されました。