資料型態 (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

這是因為幾個原因:

  1. 關係運算子"=="使用於兩個參考名稱之比較時,它比較的是兩個參考名稱是否參考至同一個物件
  2. 自動裝箱機制對於整數值 -128 到 127 之間的值,在裝箱為物件之後,會存在記憶體之中一直被重複使用

    所以iRef1和iRef2指到同一個物件 iRef3和iRef4指到不同個物件

  3. 使用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

results matching ""

    No results matching ""