Java 之 資料型別與型別轉換
一、資料型別
1、資料型別分類
Java 中資料型別分為兩大類:
基本資料型別:整數、浮點數、字元型、布林型
引用資料型別(物件型別):類、陣列、字串、介面等。
2、基本資料型別
四類八種基本資料型別:
資料型別 | 關鍵字 | 記憶體佔用 | 取值範圍 |
位元組型 | byte | 1個位元組 | -128~127 |
短整形 | short | 2個位元組 | -32768~32767 |
整形 | int(預設) | 4個位元組 | -2的31次方~2的31次方-1 |
長整型 | long | 8個位元組 | -2的63次方~2的63次方-1 |
單精度浮點型 | float |
4個位元組 | 1.4013E-45~3.4028E+38 |
雙精度浮點型 | double(預設) | 8個位元組 | 4.9E-324~1.7977E+308 |
字元型 | char | 2個位元組 | 0~65535 |
布林型別 | boolean | 1個位元組 | true、false |
二、八種基本資料型別
1、整數型別
整數型別:byte、short、int、long
Java 各整數型別有固定的表示範圍和欄位長度,不受具體OS的影響,以保證Java程式的可移植性。
Java 的整型常量預設為 int 型,宣告 long 型常量須後加 “l” 或 “L”。
Java 程式中變數通常宣告為 int 型,除非不足以表達較大的數,才使用 long。
bit:計算機中最小的儲存單位。
byte:計算機中基本的儲存單元。
整數用來儲存整數數值,可以是正整數、負數,有3種表示形式:
0B101 // 二進位制
-88 // 十進位制
0123 //八進位制必須以 0 開頭
0x25 // 十六進位制必須以 0X 或 0x 開頭
2、浮點數型別
浮點數型別:float、double
與整數型別類似, Java 浮點型別也有固定的表數範圍和欄位長度,不受具體作業系統的影響。
浮點型常量有兩種表示形式:
十進位制數形式:如:5.12 512.0f .512(必須有小數點)
科學計數法形式:如:5.12e2 512E2 100E-2
float:單精度,位數可以精確到7位有效數字。很多情況下,精度很難滿足需求。
double:雙精度,精度是 float 的兩倍,通常採用此型別。
Java 的浮點型常量預設為 double 型,宣告 float 型常量,後面必須加 ‘f’ 或 'F'。
例如:
通過上面的程式可以看出,最終的結果並非我們預料的結果,float和double型別運算可能造成精度丟失問題。
3、字元型別(Java中使用Unicode編碼來表示)
char 型資料用來表示通常意義上“字元”(2個位元組)
Java中的所有字元都使用Unicode編碼,故一個字元可以儲存一個字母,一個漢字,或其他書面語的一個字元。
字串變數的三種表現形式:
(1)字元常量是用單引號('')括起來的單個字元。
例如: char c1 = 'a'; char c2= '中'; char c3 = '9';
(2)Java中還允許使用轉義字元 '\' 來將其後的字元轉變為特殊字元常量。
例如: char c3 = ‘\n’; // '\n'表示換行符
(3)直接使用 Unicode 值來表示字元型常量。
‘\uXXXX’。其中, XXXX代表一個十六進位制整數。如: \u000a 表示 \n。
常用轉義字元:
Tips:char型別是可以進行運算的。因為它都對應有Unicode碼。
4、布林型別
布林型別:boolean
boolean 型別用來判斷邏輯條件,一般用於程式流程控制。
boolean 型別資料只允許取值 true 和 false,無 null。
注意:不可以使用 0 或 非0的整數替代 false 和 true。
Java虛擬機器中沒有任何供boolean值專用的位元組碼指令, Java語言表達所操作的boolean值,在編譯之後都使用java虛擬機器中的int資料型別來代替: true用1表示, false
用0表示。 ———《java虛擬機器規範 8版》
5、小結
(1)Java中的預設型別:整形型別是 int、浮點型別是 double。
(2)字串不是基本型別,而是引用型別。
(3)浮點型可能只是一個近似值,並非精確的值。
(4)資料範圍與位元組數不一定相關,例如float資料範圍比long更加廣泛,但是float是4位元組,long是8位元組。
(5)浮點數當中預設型別是double。如果一定要使用float型別,需要加上一個字尾F。如果是整數,預設為int型別,如果一定要使用long型別,需要加上一個字尾L。推薦使用大寫字母后綴。
三、資料型別轉換
型別轉換是從一種型別更改為另一種型別的過程。如果從低精度資料型別向高精度轉換,則永遠不會溢位,總是成功。相反,從高精度向低精度轉換,可能出現資訊丟失,有可能失敗。
1、自動型別轉換(隱式轉換)
容量小的型別自動轉換為容量大的資料型別。
資料型別按容量大小排序為:
有多種型別的資料混合運算時,系統首先自動將所有資料轉換成容量最大的那種資料型別,然後再進行計算。
注意:
(1)byte、short、char 之間不會相互轉換,他們三者在計算時首先轉換成 int 型別。
(2)boolean 型別不能與其他資料型別運算。
(3)當把任何基本資料型別的值和字串(String)進行連線運算時(+),基本資料型別的值將自動轉化為字串(String)型別。
Demo:
public static void main(String[] args) {
int i =1;
byte b = 2;
// byte x = b + 1; 報錯
// int型別和 byte 型別運算,結果是 int型別
int j = b + i;
System.out.println(j);
}
轉換原理圖解:
byte 型別記憶體佔有1個位元組,在和 int 型別運算會提升為 int 型別,自動補充 3個位元組,因此計算後的結果是 int 型別。
轉換規則:範圍小的型別向範圍大的型別提升,byte、short、char 進行算術運算時直接提升為 int 型別。
總結:
a、特點:程式碼不需要進行特殊處理,自動完成;
b、規則:資料範圍從小到大;
2、強制型別轉換(顯示轉換)
(1)自動型別轉換的逆過程,將容量大的資料型別轉換為容量小的資料型別。使用時要加上強制轉換符:(),但可能造成精度降低或溢位,格外要注意。
(2)字串型別不能直接轉換為基本型別,但通過基本型別對應的包裝類則可以實現把字串轉換成基本型別。
如: String a = “43”; int i = Integer.parseInt(a);
(3)boolean 型別不可以轉換為其他的資料型別。
強制型別轉換:
資料型別 變數名 = (資料型別) 被轉資料值;
Demo:
1 public static void main(String[] args){
2 // short 型別變數,記憶體中2個位元組
3 short s = 1;
4 /*
5 出現編譯失敗
6 s 和 1做運算的時候,1是int型別,s 會被提升為 int 型別
7 s+1 後的結果是 int 型別,將結果在賦值 short 型別時發生錯誤
8 short 記憶體2個位元組,int 型別4個位元組
9 必須將 int 強制轉成 short 才能完成賦值
10 */
11 s = s + 1; // 編譯失敗
12 s= (short) (s+1); // 編譯成功
13 }
轉換原理圖解:
注意:
a、浮點轉成整數,直接取掉小數點,可能造成資料損失精度。
b、int 強制轉成 short 取掉2個位元組(溢位),可能造成資料丟失。
總結:
a、特點:程式碼需要進行特殊的格式處理,不能自動完成。
b、格式:範圍小的型別 範圍小的變數名 = (範圍小的型別) 原本範圍大的資料;
注意事項:
a、強制型別轉換一般不推薦使用,因為有可能發生精度損失、資料溢位。
b、 byte/short/char 這三種類型都可以發生數學運算,例如加法“+”.
c、 byte/short/char 這三種類型在運算的時候,都會被首先提升成為int型別,然後再計算。
d、 boolean 型別不能發生資料型別轉換
3、 ASCII 編碼表
字元與數字的對照關係表(編碼表):當有 字元 型別的變數參與運算的時候,會把字元轉變為相應的數字,然後再進行計算。
將所有的英文字母,數字,符號都和十進位制進行了對應,因此產生了世界上第一張編碼表ASCII( American Standard Code for Information Interchange 美國標準資訊交換碼),裡面只有字母數字和常用符號,並沒有漢字。
Unicode碼錶:萬國碼。也是數字和符號的對照關係,開頭0-127部分和ASCII完全一樣,但是從128開始包含有更多字元。
Tips:
在 char 型別和 int 型別計算的過程中,char 型別的字元先查詢編碼表,得到97,再和1求和,結果為98。char型別提升 為了int型別。char型別記憶體2個位元組,int型別記憶體4個位元組。
四、String 型別
1、String 不是基本資料型別,屬於引用資料型別。
2、使用方式與基本資料型別一致。
例如:
String str = “abcd”;
3、一個字串可以串接另一個字串,也可以直接串接其他型別的資料。
str = str + “xyz” ;
int n = 100;
str = str + n;
五、擴充套件知識(編譯器的兩點優化)
1、自動型別轉換問題
對於byte/short/char三種類型來說,如果右側賦值的數值沒有超過範圍,那麼javac編譯器將會自動隱含地為我們補上一個(byte)(short)(char)。
(1)如果沒有超過左側的範圍,編譯器補上強轉。
(2)如果右側超過了左側範圍,那麼直接編譯器報錯。
Demo:
1 // 右側確實是一個int數字,但是沒有超過左側的範圍,就是正確的。
2 // int --> byte,不是自動型別轉換
3 byte num1 = /*(byte)*/ 30; // 右側沒有超過左側的範圍
4 System.out.println(num1); // 30
5
6 // byte num2 = 128; // 右側超過了左側的範圍,編譯不通過
7
8 // int --> char,沒有超過範圍
9 // 編譯器將會自動補上一個隱含的(char)
10 char zifu = /*(char)*/ 65;
11 System.out.println(zifu); // A
2、編譯器的常量優化
在給變數進行賦值的時候,如果右側的表示式當中全都是常量,沒有任何變數,那麼編譯器javac將會直接將若干個常量表達式計算得到結果。
short result = 5 + 8; // 等號右邊全都是常量,沒有任何變數參與運算編譯之後,得到的 .class位元組碼檔案當中相當於【直接就是】:short result = 13; (右側的常量結果數值,沒有超過左側範圍,所以正確。)
注意:一旦表示式當中有變數參與,那麼就不能進行這種優化了。
Demo:
1 public static void main(String[] args) {
2 short num1 = 10; // 正確寫法,右側沒有超過左側的範圍,
3
4 short a = 5;
5 short b = 8;
6 // short + short --> int + int --> int
7 // short result = a + b; // 錯誤寫法!左側需要是int型別,含有兩個變數
8
9 // 右側不用變數,而是採用常量,而且只有兩個常量,沒有其他
10 short result = 5 + 8;
11 System.out.println(result);
12
13 short result2 = 5 + a + 8; // 18 錯誤,裡面有變數
14 }