簡體   English   中英

原始類型“short” - 在 Java 中進行轉換

[英]Primitive type 'short' - casting in Java

我有一個關於 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范圍內 - short 值的范圍是 {-32,768, 32767}。 當我想執行操作時,我也需要強制轉換 -、*、/(我沒有檢查其他人)。

如果我對原始類型int執行相同的操作,則不需要將 aa+bb 轉換為int 以下工作正常:

int aa = 2;
int bb = 3;
int cc = aa +bb;

我在設計一個類時發現了這一點,我需要添加兩個類型為 short 的變量,編譯器希望我進行強制轉換。 如果我使用兩個int類型的變量執行此操作,則不需要強制轉換。

一個小小的評論:同樣的事情也會發生在原始類型byte 所以,這有效:

byte a = 2;
byte b = 3;
byte c = (byte) (a + b);

但這不是:

byte a = 2;
byte b = 3;
byte c = a + b;

對於longfloatdoubleint ,不需要強制轉換。 僅適用於short值和byte值。

簡短的 C# 中所述(但也適用於其他語言編譯器,如 Java)

存在從 short 到 int、long、float、double 或 decimal 的預定義隱式轉換。

您不能將較大存儲大小的非文字數字類型隱式轉換為 short(有關整數類型的存儲大小,請參閱整數類型表)。 例如,考慮以下兩個短變量 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 的一個重要特性,因為這種編程語言旨在用於 Internet 上的分布式應用程序。 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 是唯一的無符號整數類型。 它的值代表 Unicode 字符,從\\￿ ,即從 0 到 2 16 -1。

如果整數運算符具有 long 類型的操作數,則另一個操作數也將轉換為 long 類型。 否則,對 int 類型的操作數執行操作,如有必要,較短的操作數將轉換為 int 轉換規則是准確指定的。

【摘自計算機理論電子筆記82第2期(2003)
Blesner-Blech-COCV 2003: Sabine GLESNER 、Jan Olaf BLECH、
Fakultät für Informatik,
卡爾斯魯厄大學
德國卡爾斯魯厄]

編輯:好的,現在我們知道它是 Java...

Java 語言規范的第 4.2.2 節指出:

Java 編程語言提供了許多作用於整數值的運算符:

[...]

  • 數值運算符,產生 int 或 long 類型的值:
  • [...]
  • 加法運算符 + 和 -(第 15.18 節)

  • 換句話說,它就像 C# - 加法運算符(當應用於整數類型時)只會導致intlong ,這就是為什么您需要強制轉換以分配給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 節中。 此外,定義了十進制加法:

    decimal operator +(decimal x, decimal y);
    

    (枚舉添加、字符串連接和委托組合也在那里定義。)

    如您所見,沒有short operator +(short x, short y)運算符 - 因此兩個操作數都隱式轉換為 int,並使用 int 形式。 這意味着結果是“int”類型的表達式,因此需要進行轉換。

    在 C# 和 Java 中,賦值右側的算術表達式默認計算為 int。 這就是您需要轉換回 short 的原因,因為出於顯而易見的原因,沒有從 int 到 short 的隱式轉換。

    鑒於“為什么默認為 int”的問題尚未得到解答......

    首先,“默認”並不是真正正確的術語(盡管足夠接近)。 正如 VonC 所指出的,由 int 和 long 組成的表達式將產生 long 結果。 由整數/日志和雙精度組成的操作將產生雙精度結果。 編譯器將表達式的項提升為在結果中提供更大范圍和/或精度的任何類型(假定浮點類型具有比整數更大的范圍和精度,盡管將大 long 轉換為 double 確實會失去精度)。

    需要注意的是,此促銷活動僅適用於需要它的條款。 因此,在下面的示例中,子表達式 5/4 僅使用整數值並使用整數數學執行,即使整個表達式涉及雙精度。 結果不是你所期望的......

    (5/4) * 1000.0
    

    好的,那么為什么 byte 和 short 被提升為 int 呢? 沒有任何參考來支持我,這是由於實用性:字節碼數量有限。

    “字節碼”,顧名思義,使用單個字節來指定操作。 例如iadd ,它添加了兩個整數。 目前, 定義了 205 個操作碼,並且整數數學計算每種類型需要18 個(即 integer 和 long 之間總共 36 個),不包括轉換運算符。

    如果簡短,並且每個字節都有自己的一組操作碼,那么您將達到 241,從而限制了 JVM 的擴展能力。 正如我所說,沒有參考資料支持我這一點,但我懷疑 Gosling 等人說“人們實際上多久使用一次短褲?” 另一方面,將 byte 提升為 int 會導致這種不太好的效果(預期答案是 96,實際是 -16):

    byte x = (byte)0xC0;
    System.out.println(x >> 2);
    

    你使用什么語言?

    許多基於 C 的語言都有一個規則,即任何數學表達式都以 int 或更大的大小執行。 因此,一旦添加了兩個短褲,結果就是 int 類型。 這導致需要演員。

    Java 總是使用至少 32 位值進行計算。 這是由於 1995 年引入 java 時常見的 32 位體系結構。 CPU 中的寄存器大小為 32 位,算術邏輯單元接受 2 個 cpu 寄存器長度的數字。 因此,CPU 針對這些值進行了優化。

    這就是為什么所有支持算術運算且少於 32 位的數據類型在您使用它們進行計算時立即轉換為 int(32 位)的原因。

    所以總結起來主要是由於性能問題,現在為了兼容性而保留。

    任何低於“int”(布爾值除外)的數據類型都會隱式轉換為“int”。

    在你的情況下:

    short a = 2;
    short b = 3;
    short c = a + b;
    

    (a+b) 的結果被隱式轉換為 int。 現在你將它分配給“short”。所以你得到了錯誤。

    short,byte,char——對於所有這些我們都會得到同樣的錯誤。

    在java中,每個數字表達式都像:

    anyPrimitive zas = 1;
    anyPrimitive bar = 3;
    ?? x = zas  + bar 
    

    如果加法元素之一是 long,則 x 將始終至少是 int 或 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變量,則編譯器可以確保它們的總和值 5 可以分配給byte類型的變量,而不會損失任何精度。 在這種情況下,編譯器最好將 a 和 b 的總和分配給 c 。 這是修改后的代碼:

    final byte a = 2;
    final byte b = 3;
    byte c = a + b;
    

    我想補充一些尚未指出的內容。 Java 不考慮您在...中為變量(2 和 3)提供的值

    短 a = 2; 短 b = 3; 短 c = a + b;

    所以據Java所知,你可以做到這一點......

    空頭 a = 32767; 短 b = 32767; 短 c = a + b;

    這將超出short的范圍,它將結果自動裝箱為int,因為“可能”結果將超過short但不超過int。 Int 被選為“默認值”,因為基本上大多數人不會硬編碼值高於 2,147,483,647 或低於 -2,147,483,648

    如果兩個值具有不同的數據類型,那么 java 會自動將其中一個值提升為兩個數據類型中較大的一個。 在您的情況下,較小的數據類型(例如 byte、short 和 char)將在任何時候與二元算術運算符一起使用時“提升”為 int。 如果兩個操作數都不是 int,這仍然是正確的。

    short x = 10;
    short y = 20;
    short z = x+y // this will be a compiler error. To solve this then casting would be required
    short z = (short)(x+y) // this will return 30
    short z = (short) x+y //this will return a compiler error
    

    請記住,轉換是一元運算符,因此通過將較大的值轉換為較小的數據類型,您實際上是在告訴編譯器忽略默認行為。

    暫無
    暫無

    聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

     
    粵ICP備18138465號  © 2020-2024 STACKOOM.COM