Java內存管理-你真的理解Java中的數據類型嗎(十)

作一個積極的人java

編碼、改bug、提高本身git

我有一個樂園,面向編程,春暖花開!程序員

推薦閱讀面試

第一季

0、Java的線程安全、單例模式、JVM內存結構等知識梳理編程

一、Java內存管理-程序運行過程(一)設計模式

二、Java內存管理-初始JVM和JVM啓動流程(二)數組

三、Java內存管理-JVM內存模型以及JDK7和JDK8內存模型對比總結(三)緩存

四、Java內存管理-掌握虛擬機類加載機制(四)安全

五、Java內存管理-掌握虛擬機類加載器(五)ide

六、Java內存管理-類加載器的核心源碼和設計模式(六)

七、Java內存管理-掌握自定義類加載器的實現(七)
第一季總結:由淺入深JAVA內存管理 Core Story

第二季

八、Java內存管理-愚人節new一個對象送給你(八)

【福利】JVM系列學習資源無套路贈送

九、Java內存管理-」一文掌握虛擬機建立對象的祕密」(九)

十、Java內存管理-你真的理解Java中的數據類型嗎(十)

十一、Java內存管理-Stackoverflow問答-Java是傳值仍是傳引用?(十一)

十二、Java內存管理-探索Java中字符串String(十二)

實戰

一文學會Java死鎖和CPU 100% 問題的排查技巧

分享一位老師的人工智能教程。零基礎!通俗易懂!風趣幽默!你們能夠看看是否對本身有幫助,點擊這裏查看【人工智能教程】。接下來進入正文。

勿在流沙築高臺,出來混早晚要還的。

做爲Java程序員,Java 的數據類型這個是必定要知道的! 可是無論是那種數據類型最終存儲都要到內存中,本文由淺入深對數據類型進行介紹和講解,相信讀完本文你必定會有收穫的,會對Java數據類型有更深的瞭解和認識!

本文地圖

1、什麼是位、字節、字符、字符集

位(bit):計算機內部存儲數據的最小單位,音譯爲比特,每一個二進制數字0或者1就是1個位!

字節(Byte):計算機存儲容量(數據處理)的基本單位,音譯拜特,8個位構成一個字節;即:1 byte (字節)= 8 bit(位)。

一個字節可以存放的數字範圍用二進制表示爲000000000~11111111,也就是8個bit(比特),8個比特轉換爲無符號的10進制數字範圍是0~255,轉換爲有符號數據通常爲-128~127。

字節說明:對於存儲容量,咱們是比較熟悉的,計算機存儲容量大小以字節數來度量,1024進位制:

1024B=1K(千)B (1024個字節等於 1KB)
1024KB=1M(兆)B
1024MB=1G(吉)B
1024GB=1T(太)B
還有PB、EB、ZB、YB 、NB、DB等複製代碼

字符:字符是一種符號,同以上說的存儲單位不是一回事。指計算機中使用的字母、數字、字和符號,包括:一、二、三、A、B、C、~!·#¥%……—*()——+等等。字符通常在不一樣的編碼(字符集)下面佔用的字節數不一樣!也即佔用存儲空間不一樣!

編碼:編碼就是一個編號(數字)到字符的一種映射關係(集合),常見的有 ASCII、ISO-8859-一、GB23十二、GBK、UTF-八、UTF-16 等。它們均可以被看做爲字典,它們規定了轉化的規則,按照這個規則就可讓計算機正確的表示咱們的字符。

# 簡單舉例舉例:
在 ASCII 編碼中,一個英文字母字符存儲須要1個字節。
在 GB 2312 編碼或 GBK 編碼中,一個漢字字符存儲須要2個字節。
在UTF-8編碼中,一個英文字母字符存儲須要1個字節,一個漢字字符儲存須要3到4個字節。
在UTF-16編碼中,一個英文字母字符或一個漢字字符存儲都須要2個字節(Unicode擴展區的一些漢字存儲須要4個字節)。
在UTF-32編碼中,世界上任何字符的存儲都須要4個字節。複製代碼

tips:

ASCII碼是最熟知字符編碼,編碼範圍爲0~255,屬於單字節編碼。ASCII碼編碼範圍過小了,Java爲了可以處理多字節語言編碼(好比中文、日文、韓文等)編碼範圍0x000000~0x10FFFF,採用國際組織制定的Unicode編碼集。

由於Unicode編碼並不是連續的,全部將Unicode轉換爲具體的數值格式是又有多種不一樣的轉換方式。稱爲Unicode Translation Format(UTF)。

簡單總結一下UTF-八、UTF-1六、UTF-32三種轉換方式,都是採用字節做爲編碼的基本單位!

轉換方式 特色
優勢
缺點
UTF-8
變長編碼,1-4字節 節省空間
轉換麻煩
UTF-16
固定編碼,2字節
轉換相對簡單 空間相對節省
UTF-32
固定編碼,4字節
轉換簡單
空間最浪費

目前使用UTF-8仍是比較多,節省空間仍是很大的優點! 在說明一點Java虛擬機內部使用的UTF-16轉換方式,固定使用兩個字節,因此java中字符char 佔用 2個字節!

編碼這一塊的內容其實挺多,如需瞭解更多深刻細節,請自行查閱相關資料!

2、基本數據類型和引用數據類型

有學過C語言的夥伴知道在C語言中能夠聲明指針類型的變量,可是在Java語言中是看不到使用指針的,那麼Java中有沒有指針呢?準確的話是有的,由於在Java底層有些類型是封裝了指針的。在Java中根據底層是否封裝了指針能夠將Java的數據類型分爲兩類,值類型和引用類型

數據類型

2.一、值類型

值類型: 也稱爲基本數據類型和基元數據類型。它的值就是一個數字,一個字符或一個布爾值等。

沒有封裝指針的變量,它們在Java中有8個,包括bytecharshortintfloatlongdouble boolean

這些基本類型首字母都是小寫,它們並非類,也沒有屬性和方法。聲明值類型變量,只會在中分配一塊內存空間。

值類型

這裏面還有一個知識點是: 自動類型轉換強制類型轉換

自動類型轉換

通常狀況下Java中會將佔用內存空間較低的類型轉換爲較高類型,如 int型的變量和 long型的變量進行計算的時候,會將int型轉換爲long型;

若是兩個變量佔用內存空間同樣,可是一個是整型,一個是浮點型,則會將整型轉換爲浮點型。如int型變量與float型變量進行計算,會將int型轉換爲float型。

強制類型轉換:

第一種狀況:提高變量的類型級別,以獲取精度更高的計算結果! 好比 兩個整型int變量進行除法運算,爲了精度更高,強制轉爲long類型!

第二種狀況:須要用佔用空間較小的變量類型接受佔用空間較大的變量類型。好比 int轉爲byte等,可是要注意 轉換過程當中產生溢出截斷的狀況!

上面圖中內容中沒有boolean類型變量進行說明,由於boolean類型比較特殊。boolean類型變量只有兩個值,true或者false,它不參與數學運算,也不能與其餘類型變量進行轉換(無論自動轉換仍是強制轉換),只是用來進行邏輯判斷。

boolean類型變量的內存空間佔用具備必定的不肯定性,理論上一個比特就能夠保存boolean類型變量的值,當由於內存使用的最小單位是字節,那麼變量不可能僅佔用1/8個字節。實際中,根據編譯器的不一樣,Java會使用1~4字節來保存boolean變量。字節內容均爲0表示false。只要有字節爲非0值表示true。

面試必定要注意 :String 不是基本類型!

2.二、引用類型

引用類型: 就是底層封裝指針的數據類型。這部分包含的比較多,好比咱們自定義或者系統的、抽象類、接口,以及數組。它們在內存中分配兩塊空間,首先要在棧上給其引用(句柄)分配一塊內存(不存放具體數值),而後對象的具體信息都存儲在堆內存上(如對象的屬性值等),最後由棧上面的引用指向堆中對象的地址。

2.三、簡單示例

示例代碼:

public class PrettyGirl {
    /**
     * 姑娘姓字名誰
     */
    String name;

    /**
     * 芳齡幾何
     */
    int age;

    public static void main(String[] args) {
        //  PrettyGirl是自定義類,是引用類型,分配兩塊內存空間
        PrettyGirl prettyGirl = new PrettyGirl();

        // String類是系統類,也是引用類型,分配兩塊內存空間
        String name = new String("Java ok");

        // int,float 是值類型,只分配一塊內存空間
        int num = 10;
        float price = 110.10f;

        // 對象名.屬性名訪問對象的屬性,訪問包括賦值和取值
        prettyGirl.name = "Alice";
        prettyGirl.age = 25;

    }

}複製代碼

經過類名 對象名 = new 類名()建立對象, 在 PrettyGirl prettyGirl = new PrettyGirl();這行代碼在內存中就建立了兩塊內存空間,第一塊在棧中,名字叫 prettyGirl,它是一個引用地址,並不放具體的數值,第二塊堆中的內存才存放具體的數值,如name,age等信息。

其實數組內部也是封裝引用(指針),即使是基本類型的數組,也是如此! 數組也是引用類型!好比

int[] nums = new int[]{1,4,7,3,9};複製代碼

說明 :0x001 是我隨便寫的一個值,真實的內存地址並非這個,這個值只是爲了我畫圖方便!

在多強調一點,在引用類型中,對於類來講,要建立對象其實包括兩步,第一是聲明對象,第二是建立對象!

public static void main(String[] args) {
    // 聲明對象,至關分配指針類型變量,在棧中分配內存
    PrettyGirl alice;
    // 建立對象,建立具體內存空間,在堆中分配內存
    alice = new PrettyGirl();
}複製代碼

聲明對象:就至關於在棧中聲明引用類型的變量,它的內存不存放具體的數值,而只存放另外一塊堆中內存的地址!如

PrettyGirl alice;複製代碼

建立對象:通常使用new關鍵字,以下代碼

alice = new PrettyGirl();複製代碼

上面這一行代碼作了兩件事情,首先在堆中分配一塊存放具體數值的內存,而後將這個內存的首地址賦給上面聲明的引用變量!

其實不少時候,對象的聲明和建立是放在一行的,以下:

PrettyGirl mary = new PrettyGirl();複製代碼

3、 八種基本類型的包裝類和常量池

如下內容摘自:參考資料1 中 8種基本類型的包裝類和常量池部份內容!

Java 基本類型的包裝類的大部分都實現了常量池技術,即Byte,Short,Integer,Long,Character,Boolean;這5種包裝類默認建立了數值[-128,127]的相應類型的緩存數據,可是超出此範圍仍然會去建立新的對象

兩種浮點數類型的包裝類 Float,Double 並無實現常量池技術。

Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);// 輸出true
Integer i11 = 333;
Integer i22 = 333;
System.out.println(i11 == i22);// 輸出false
Double i3 = 1.2;
Double i4 = 1.2;
System.out.println(i3 == i4);// 輸出false, 無緩存!複製代碼

Integer 緩存源代碼:

/**
*此方法將始終緩存-128到127(包括端點)範圍內的值,並能夠緩存此範圍以外的其餘值。
*/
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}複製代碼

對於Integer類型來講,值在-128-127,用==比較是一致的,超過這個區間就不行了。

應用場景:

  1. Integer i1=40;Java 在編譯的時候會直接將代碼封裝成Integer i1=Integer.valueOf(40);,從而使用常量池中的對象。
  2. Integer i1 = new Integer(40);這種狀況下會建立新的對象。
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//輸出false複製代碼

最後在貼出阿里巴巴Java手冊中對包裝類使用的建議:

4、本文總結

本文總體內容相對基礎,可是在java開發中仍是很是重要,注重細節和基礎,讓寫出的每一行代碼都是最優的!朝着這個方向努力! 下一篇整理一下值傳遞和引用傳遞! 敬請期待!

備註: 因爲本人能力有限,文中如有錯誤之處,歡迎指正。

5、參考資料

一、多是把Java內存區域講的最清楚的一篇文章

二、Java語言中一個字符佔幾個字節?

謝謝你的閱讀,若是您以爲這篇博文對你有幫助,請點贊或者喜歡,讓更多的人看到!祝你天天開心愉快!

Java編程技術樂園:一個分享編程知識的公衆號。跟着老司機一塊兒學習乾貨技術知識,天天進步一點點,讓小的積累,帶來大的改變!

掃描關注,後臺回覆【資源】,獲取珍藏乾貨! 99.9%的夥伴都很喜歡

image.png | center| 747x519

© 天天都在變得更好的阿飛雲
相關文章
相關標籤/搜索