深入理解Java之數據類型


一、概述

    我們通過編程解決一個具體問題時,首先要做的工作是用各種“數據結構”表示問題中的實體對象,而后才能着手研究描述具體業務邏輯的算法。這也正印證了”程序 = 數據結構 + 算法“。而這里的數據結構,便對應着各種數據類型。

    數據類型指的是一組值以及相關的一組操作。Java中有兩大類數據類型:一類是原始(primitive)數據類型,包括boolean、int、double等等;還有一類是引用類型,也就是類(class),包括Java類庫提供給我們的類和我們自己使用關鍵字class定義的類。Java中的類按功能來分又可以分為抽象數據類型和靜態代碼庫。

 

二、原始數據類型

1. 聲明與初始化

    原始數據類型作為變量使用的場景主要有兩種:

一是作為局部變量使用,這時我們必須聲明並且初始化后才能使用,否則會報錯:

public static void main() {
    int a;
    int b = a + 1; //錯誤,局部變量a沒有初始化
    ...
}

 

第二種場景是作為實例變量或類變量使用,這時聲明后若不初始化系統會“隱式初始化”(具體來說是整型初始化為0,浮點型初始化為0.0,布爾型初始化為false):

public class Counter {
    private int id;
    private int count;

    public Counter(int id) { //在構造器中沒有顯示初始化count,count在新創建的對象中會被系統隱式初始化為0
        this.id = id;
    }
    ...
}

 

2. 原始類型數組

    在上面我們提到過,Java中除了原始數據類型便是引用類型,因此Java中的數組是一種引用類型。引用類型與原始數據類型的本質區別在於:引用類型變量存放的是一個引用,這里的引用也就是內存地址。 考慮下面的代碼片段:

...
int a = 12345;
int b = a;
b = 123456; //a的值不變,仍為12345
...
int[] d = {1, 2, 3};
int[] e = d;
e[0] = 0;  //改變了e的同時也改變了d,即現在d = {0, 2, 3}
...

    在上面的代碼中,”int b = a"這句會創建一個a的副本,並把它賦值給b,由於是原始數據類型,所以修改b的值不會影響到a。

    而“int e = d”同樣也先創建一個d的副本,再把他賦值給e,然而d的值實際上是整型數組的引用(也就是地址),所以e的值也變成了同一個整型數組的地址。所以通過e對該整形數組做的改變會反映到d上。這個現象叫做起別名,也就是內存中同一個整型數組現在有不只一個變量存放着它的地址,這倆變量都能對它就行修改。

    

三、引用類型

    正如上文提到的,Java中的引用類型變量的值是一個引用,也就是實際對象的地址。Java中的引用類型也就是我們常說的類(class),類主要有兩種用途:一是用來描述一種抽象數據類型(Abstract Data Type,ADT);另一種是用來容納一組靜態方法,也就是用做靜態代碼庫(比如,Java類庫中的Math類)。

    1. 內存模型

    Java中的引用類型的內存占用情況,不如原始類型來的直觀。原始類型變量不需要保存除了它本身的值之外的任何信息。而一個Java對象往往占用了更多的內存,它需要保存它的所有實例變量以及一些額外信息(包括指向對象的類的引用、垃圾收集信息、同步信息)。考慮以下的Java類:

public class Rect {
    private int l;
    private int w;
    ...
}

    一個Rect類型的對象在一個典型的64位機器上會占用24字節的內存,其中包括8字節的指向Rect類的引用、8字節的垃圾收集信息及同步信息和兩個int類型的實例變量各占4字節。

    

    2. 相等性

    “==”運算符對兩個對象默認比較行為是檢測他們的標識(即引用)是否相等。而在多數情況下,我們對兩個對象相等的定義是,這兩個對象的狀態(各個實例變量的值)相等。要想實現這種我們想要的行為,只需要重寫equals()方法。

    這個方法定義在Object類(一切Java類的父類),Java標准要求這個方法的實現必須接受一個Object類型參數,並滿足以下性質:

(1)自反性:即x.equals(x)必須返回true

(2)對稱性:x.equals(y)與y.equals(x)的返回結果必須相同

(3)傳遞性:若x.equals(y), y.equals(z)均返回true,那么x.equals(z)也必須返回true

(4)一致性:若x與y引用的對象沒變,那么無論多少次調用x.equals(y)都應返回一致的結果

(5)非空性:對於任何的非空引用x,x.equals(null)總是返回false

    拿以上提到的Rect類為例:

public class Rect {
    private int w;
    private int l;

    public Rect(int w, int l) {
        ...
    }

    public boolean equals(Object otherObject) {
        if (otherObjcet == null) {
            return false; 
        } else if (this == otherObject) {
            return true;     //標識相同,直接返回true
        }
        if (this.getClass() != otherObject.getClass()) {
            return false;
        }
        Rect rect = (Rect) otherObject;
        if ((this.getW() == rect.getW()) && ((this.getL() == rect.getL())) {
            return true;
        }
        return false;
    }
}
            

    這里需要注意的是,在實際應用中,不同對象的相等性定義往往是具體場景而定,這里我們定義兩個矩形對象相等是指兩者的長和寬分別相等。

 

    3.不變性

    在Java中,用final修飾的數據類型具有“不變性”。而這個不變性對於原始數據類型和引用類型來說有着不同的含義。對於原始數據類型變量來說,所謂的不變性是指它的值不可改變;對於引用類型變量來說,不變性指的是它所引用的對象不可發生改變,但是它所引用的對象的內容可以改變。另外,final修飾的類不可以再派生子類。比如以下代碼段:

public Class Test {
    public static final int a = 5; //a的值將一直為5,不可更改
    public final double[] b; //double數組對象b的標識(引用)不可邊,但是它指向的double數組可以更改
    ...
}

 

   

【這篇博文簡單的記錄下自己的一些學習所得,如有不准確之處歡迎大家指正:)】

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM