資料型態 (Data type)
基本型態(Primitive Type)
可分作四個大類
- 整數型態(Integral type)-byte、short、int 和 long
- 浮點數型態(Floating point type)-float 和 double
- 字元型態(Textual type)-char
- 邏輯型態(Logical type)-boolean
[整數型態(Integral type)]
在 Java 程式語言中共有四個整數基本型態,分別以 byte、short、int 和 long 四個關鍵字來識別。
這些型態以不使用小數點的方式來儲存數字。
整數值有大有小,所以整數中才又區分有四種不同的資料型態,
以儲存人的年齡為例,byte 的變數型態就可以滿足儲存的要求,因為 byte 型態的範圍已涵蓋了人們年齡的範圍。
表 4-1 表格列出所有整數型態、包含它們所使用的記憶體容量大小以及所有可能值的範圍。
型態 | 長度 | 範圍 | 範例 |
---|---|---|---|
byte | 8 bits | -128 到 127 共 256 個 | 2、-114 |
short | 16 bits | -32,768 到 32767 共 65,535 個 | 2、-3269 |
int(預設) | 32 bits | -2,147,483,648 到 2,147,483,647 共 4,294,967,296 個 | 2、147334778 |
long | 64 bits | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,808 共 18,446,744,073,709,557,616 個 | 2 、-20368547758、08L、1L |
字面值(Literal value)
直接在程式中寫下一個數值,該數值稱之為字面值(Literal value),
編譯器會自動為該數值配給記憶體空間,
以整數值為例,在一般情況下如果您寫下一個整數,編譯器將自動設定為 int 型態, 除非您自行指定或是使用 L,例如寫下 10L的話,則編譯器會為該數值配給 long 型態的空間。
System.out.println(10); //10
System.out.println(2036854775808); //[ERROR]integer number too large: 2036854775808
System.out.println(2036854775808L); //2036854775808
L 加於整數之後,這是在告知編譯器:「請為這個數值配給 long 型態的記憶體空間」
[浮點數型態(Floating point type)]
float 與 double 為浮點數的兩個型態。
它們是用來儲存右邊有出現小數點的數值,如 12.24 或 3.14159
型態 | 長度 | 範圍 |
---|---|---|
float | 32 bits | 99F、-32745699.01F、4.2E6F(工程標記記為 4.2 * 10的6次方 ) |
double(預設) | 64 bits | -1111、2.1E12、99970132745699.999 |
當您在程式中寫下一個浮點數值,編譯器預設會配給 double 型態的記憶體空間給該數值,
如果您只打算配給浮點數 float 型態的記憶體空間,則必須使用 F 來指定
[字元型態(Textual type)]
型態 | 長度 | 範圍 |
---|---|---|
char | 16 bits | '中'、'a' |
char 基本型態是用來儲存 16 bits 的單一字元,例如'Y'字元,
在 Java 程式語言中,字元必須使用單引號括住
char 型態並不會真正儲存像'Y'這樣的字元,而是將字元轉換成一連串的位元儲存。而位元與字元的對應是根據程式語言所使用的字元集所對照而成。
大多數的電腦語言都是使用 ASCII 碼(American Standard Code for Information Interchange)
ASCII 是一個 8 位元的字元集,對所有的英文字元、標點符號、數字等都有所對應。
在 Java 程式語言中所使用的是 16 位元的 Unicode 碼,
Unicode 能夠儲存在現今世界的各種語言中大部份必須顯示的字元。因此您可以用任何語言撰寫程式,程式就能夠正常地運作,並正確地顯示該語言。
為了與 ASCII 碼相容,Unicode 碼內包含有 ASCII 碼的子集合(前 128 個字元),
例如您寫了一個'Y'字元,實際上該字元在 Java 中是以 00000000 00111011 的方式儲存,編碼數值是 59,對應 ASCII 編碼表的'Y'字元。
Java 中無論是中文字元或是英文字元,一律佔 16 bits 長度的記憶體空間
[邏輯型態(Logical type)]
型態 | 長度 | 範圍 |
---|---|---|
boolean | 16 bits | '中'、'a' |
String
[String物件]
- 字串是java.lang.String 類別
- 編譯器會自定建立 String 物件來表示雙引號包括的文字
- 只要是字元內容相同,都會重複使用 String 儲存池中的同一個 String 物件
用關係運算子"=="
來驗證是不是同個物件
Integer iRef1 = 100;
Integer iRef2 = 100;
Integer iRef3 = 200;
Integer iRef4 = 200;
System.out.println("100 == 100 => "+(100 == 100));
System.out.println("200 == 200 => "+ (200 == 200));
System.out.println("iRef1 == 100 => "+ (iRef1 == 100));
System.out.println("iRef3 == 200 => "+ (iRef3 == 200));
System.out.println("iRef1 == iRef2 => "+ (iRef1 == iRef2));
System.out.println("iRef3 == iRef4 => "+ (iRef3 == iRef4));
String text1 = "Hello!";
String text2 = "Hello!";
System.out.println("Hello! == Hello! => "+ ("Hello!" == "Hello!"));
System.out.println("text1 == Hello! => "+ (text1 == "Hello!"));
System.out.println("text2 == Hello! => "+ (text2 == "Hello!"));
System.out.println("text1 == text2 => "+ (text1 == text2));
String name1 = "Justin Lin";
String name2 = new String("Justin Lin");
System.out.println("name1 == Justin Lin => " + (name1 == "Justin Lin"));
System.out.println("name2 == Justin Lin => " + (name2 == "Justin Lin"));
System.out.println("name1 == name2 => " + (name1 == name2));
/*
100 == 100 => true //值
200 == 200 => true //值
iRef1 == 100 => true //值
iRef3 == 200 => true //值
iRef1 == iRef2 => true //物件
iRef3 == iRef4 => false //物件
Hello! == Hello! => true //值
text1 == Hello! => true //值
text2 == Hello! => true //值
text1 == text2 => true //物件
name1 == Justin Lin => true //物件
name2 == Justin Lin => false //物件
name1 == name2 => false //物件
*/
[char]
可以使用字元陣列為基礎,並使用 new 關鍵字來建立String 實例
也可以指定字元陣列的開始索引,擷取字元數來建立 String 實例
char[] array = {'J', 'u', 's', 't', 'i', 'n'};
String name = new String(array);
System.out.println(name); //Justin
char[] array2 = {'J', 'u', 's', 't', 'i', 'n'};
String name2 = new String(array2, 0, 4);
System.out.println(name2); //Just
String name3 = new String(array2, 1, 4);
System.out.println(name3); //usti
型態轉換
[晉升( Promotion )]
這不是很懂...
如果變數的資料型態其儲存範圍比指定的數值之資料型態為大時,則會發生數值型態晉升的動作,
簡單的說,就是數值的型態會自動提昇為符合變數之資料型態
long money = 10;
由於變數 money 是 long 型態,資料型態自動從 int 變為 long
[轉型( Casting )]
數值的資料型態之儲存範圍比變數的資料型態為大時,由於原數值無法將所有的容量儲存至變數中,因而編譯器會提出錯誤訊息
要將資料型態大的值指定給資料型態小的變轉型數,則您必須明確進行轉型(Casting)的動作
long money = 10;
int smallMoney = money;
/*產生錯誤:
possible loss of precision
found : long
required: int
int smallMoney = money;
*/
long money = 10;
int smallMoney = (int) money;
double pi = 3.14159;
float piAlso = (float) 3.14; // 轉型為 float
Wrapper 類別
[Wrapper v.s Primitive Type]
- Primitive Type 不是物件
- 進行數值計算
- 讓編譯器為您保留一個記憶體空間
- 可以使用所宣告的變數名稱來取得該空間的值,或是將數值儲存至該空間中
- 用byte、short、int、long、float、long、char、boolean 等宣告變數
- 重新指定變數值,值會改變
- Wrapper 是物件
- 需要一個物件時,您使用 new 關鍵字加上類別名稱來建立
- 變數是用來參考至( Refer to )物件所在的記憶體空間
- 重新指定物件給 iRef 參考時,原來 iRef 所參考的物件並不會被覆蓋
int iVar1 = 10;
int iVar2 = 20;
iVar1 = iVar2;
iVar2 = 30;
System.out.println("iVar1="+iVar1);
System.out.println("iVar2="+iVar2);
//box iVar1 =20 & box iVar2 = 20
//兩個box還在,且值都變20
//iVar1=20,iVar2=30
Integer iRef1 = new Integer(10);
Integer iRef2 = new Integer(20);
iRef1 = iRef2;
iRef1 = 30;
System.out.println("iRef1="+iRef1);
System.out.println("iRef2="+iRef2);
//space 原iRef1 = 10,新的iRef1指到iRef2
//兩個變數都指到iRef2
//理論上 iRef1=30,iVar2=30
//但我跑出來iVar1=20,iVar2=30
//怪怪低
[Wrapper 類別]
Wrapper 類別來包裝基本資料型態:
基本資料型態 | Wrapper 類別 |
---|---|
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
char | java.lang.Character |
boolean | java.lang.Boolean |
Integer ageOfStudent = new Integer(20);
方法名稱 | 作用 |
---|---|
byteValue() | 將 Wrapper 的資料以 byte 型態傳回 |
doubleValue() | 將 Wrapper 的資料以 double 型態傳回 |
floatValue() | 將 Wrapper 的資料以 float 型態傳回 |
intValue() | 將 Wrapper 的資料以 int 型態傳回 |
longValue() | 將 Wrapper 的資料以 long 型態傳回 |
compareTo(Integer anotherInteger) | 與另一個 Integer 物件比較大小,傳回 0 表示相等,傳回 -1 表示小於anotherInteger,傳回 1 表示大於 anotherInteger |
public class WrapperDemo{
public static void main(String[] args){
Integer ageOfStudent = new Integer(20);
System.out.print("原來的 int 值:");
System.out.print("double 型態:");
System.out.println(
ageOfStudent.intValue());
System.out.println(
ageOfStudent.doubleValue());
Integer ageOfOther = new Integer(10);
int result =
ageOfStudent.compareTo(ageOfOther);
System.out.print("ageOfStudent");
switch (result){
case 1:
System.out.print(" 大於 ");
break;
case -1:
System.out.print(" 小於 ");
break;
case 0:
System.out.print(" 等於 ");
break;
}
System.out.println("ageOfOther");
}
}
[物件容器 ( Container )]
物件容器 ( Container )的 使 用(像是 java.util.ArrayList 、java.util.HashMap 等),儲存至物件容器的資料必須是物件,
如果您要將數值儲存至這些容器中,您也必須使用 Wrapper 類別先加以包裝。
裝箱 & 拆箱
減少處理轉型成Wrapper 和 Primitive Type
自動裝箱與拆箱機制主要是編譯器的功勞,也就是俗稱的編譯器蜜糖 ( Compiler sugar ) 或語法蜜糖 ( Syntax sugar),
稱之為蜜糖常是因為該功能雖然使用方便,但隱藏了一些容易被開發人員忽略的陷阱。
[自動裝箱 autoboxing]
自動裝箱機制對於整數值 -128 到 127 之間的值,在裝箱為物件之後,會存在記憶體之中一直被重複使用,而對於-128 到 127 之外的值,則於執行時期運行到該段程式碼時,才建立一個新的物件。
JDK5.0後,可以這樣宣告Wrapper (簡化new)
Integer iRef = new Integer(10);
//簡化
Integer iRef = 10;
但會遇到以下問題:
Integer iRef1 = 100;
Integer iRef2 = 100;
Integer iRef3 = 200;
Integer iRef4 = 200;
Integer iRef5 = new Integer(100); //取消autoboxing
Integer iRef6 = new Integer(100); //取消autoboxing
if (iRef1 == iRef2)
System.out.println("iRef1 == iRef2");
else
System.out.println("iRef1 != iRef2");
if (iRef3 == iRef4)
System.out.println("iRef3 == iRef4");
else
System.out.println("iRef3 != iRef4");
if (iRef3.equals(iRef4))
System.out.println("iRef3 == iRef4");
else
System.out.println("iRef3 != iRef4");
if (iRef5 == iRef6)
System.out.println("iRef5 == iRef6");
else
System.out.println("iRef5 != iRef6");
//iRef1 == iRef2
//iRef3 != iRef4
//iRef3 == iRef4
//iRef5 != iRef6
這是因為幾個原因:
- 當
關係運算子"=="
使用於兩個參考名稱之比較時,它比較的是兩個參考名稱是否參考至同一個物件 - 自動裝箱機制對於整數值 -128 到 127 之間的值,在裝箱為物件之後,會存在記憶體之中一直被重複使用
所以iRef1和iRef2指到同一個物件 iRef3和iRef4指到不同個物件
- 使用equals來判斷值是否相等
[拆箱 unboxing]
JDK5.0後,可以這樣宣告Wrapper (簡化.xxValue)
//已宣告: Integer iRef = 10;
int iVar = iRef.intValue();
//簡化
int iVar = iRef;
[陷阱]
Integer iRef = null;
int iVar = iRef;
//success
Integer iRef = null;
int iVar = iRef.intValue();
//error:NullPointerException