Java基礎回顧--基本數據類型包裝類 4

基本數據類型包裝類3

參考:深入剖析Java中的裝箱和拆箱;
Java中基本數據類型和包裝類互轉中 緩衝機制的使用;
java學習筆記:裝箱和拆箱,包裝器和緩衝池
Java 各 類型數據在內存中分配情況詳解

一 java內存分配

這裏只是在網上找的一些資料;
Java 中的數據類型分爲
1. 基本類型(原始數據類型) byte short int long float double char boolean
基本類型的變量持有原始值。
2. 符合數據類型(引用類型),引用類型持有引用值(即對某個對象的引用,而非對象本身)。

一般Java在內存分配時會涉及到以下區域:
1. 寄存器:我們在程序中無法控制
2. 棧:存放基本類型的數據和對象的引用但對象本身不存放在棧中,而是存放在堆中
3. 堆:存放用new產生的數據
4. 靜態域:存放在對象中用static定義的靜態成員
5. 常量池:存放常量
6. 非RAM存儲:硬盤等永久存儲空間
其中主要是堆,棧的存儲。

堆,棧

  1. 函數中定義的一些基本類型的數據變量對象的引用變量都在函數的棧內存中分配。
    棧的優勢是存取速度比堆要快,僅次於直接位於CPU 的寄存器,而且數據可以共享。但是存在棧中的數據大小與生存週期必須是確定的
    當在一段代碼塊定義一個變量時,Java就在棧中 爲這個變量分配內存空間,當該變量退出該作用域後,Java會自動釋放掉爲該變量所分配的內存空間,該內存空間可以立即被另作他用。

  2. 堆內存用來存放由new創建的對象和數組。 在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。
    在堆中產生了一個數組或對象後,還可以 在棧中定義一個特殊的變量,讓棧中這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量。
    引用變量是普通的變量,定義時在棧中分配,引用變量在程序運行到其作用域之外後被釋放。而數組和對象本身在堆中分配,即使程序 運行到使用 new 產生數組或者對象的語句所在的代碼塊之外,數組和對象本身佔據的內存不會被釋放,數組和對象在沒有引用變量指向它的時候,才變爲垃圾,不能在被使用,但仍 然佔據內存空間不放,在隨後的一個不確定的時間被垃圾回收器收走(釋放掉)。

二 基本數據類型

這種類型是通過諸如 int a=7; 的形式來定義的,稱爲自動變量。這裏自動變量是字面值。不是類的實例,即不是類的引用,這裏並沒有類的存在。a 是指向一個 int 類型的引用,指向 7 這個字面值。由於其大小確定生存期可知(這些定義在某個程序塊中,程序塊退出後,字段值就消失),因此存在中.
由於棧的數據可以共享,因此 int a=3; int b=3; 這段代碼,編譯器首先處理int a =3; ,先會在棧中創建一個變量爲 a 的引用,然後查找有沒有字面值爲 3的地址,沒有找到,就開闢一個存放 3 這個字面值的地址,然後將a 指向 3 的地址。接下來處理int b =3; 在創建完 b 這個引用變量後,由於棧中已經有 3 這個字面值,便將 b 指向 3 的地址。【定義變量,給變量賦值】

三 包裝類數據

Java中的基本類型不是面向對象的,它們只是純粹的數據,除了數值本身的信息之外,基本類型數據不帶有其他信息或者可操作方法。這在實際使用中存在很多不足,爲了解決這個不足,* 對每個基本類型都對應了一個引用的類型*,稱爲裝箱基本類型。

Java8種基本數據類型總結

序號

數據類型

大小/位數

封裝類

默認值

可表示數據範圍

1

byte()

1字節

Byte

0

-128~127

2

short(短整數)

2字節

Short

0

-32768~32767

3

int(整數)

4字節

Integer

0

-2147483648~2147483647

4

long(長整數)

8字節

Long

0

-9223372036854775808~9223372036854775807

5

float(單精度)

7

Float

0.0

1.4E-45~3.4028235E38

6

double(雙精度)

15

Double

0.0

4.9E-324~1.7976931348623157E308

7

char(字符)

2字節

Character

0~65535

8

boolean

 

Boolean

flase

truefalse


1,拆箱,裝箱

裝箱:根據數據創建對應的包裝對象。

Integer i = new Integer (3);
Integer j = 4;//jdk1.5 之後可以通過這種方式自動裝箱

拆箱:將包裝類型轉換爲基本數據類型。

int  index2 = j.intValue();
int  index1 = i;//自動拆箱

JDK1.5 爲Integer 增加了一個全新的方法:public static Integer valueOf(int i) 自動裝箱過程時,編譯器調用的是static Integer valueOf(int i)這個方法 於是Integer a=3; ==>Integer a=Integer.valueOf(3);

此方法與new Integer(i)的不同處在於:
方法一調用類方法返回一個表示 指定的 int 值的 Integer 實例。方法二產生一個新的Integer 對象。

2,緩衝機制

JDK API文檔中對這個新的valueOf方法有明確的解釋:
如果不需要新的 Integer 實例,則通常應優先使用該方法,而不是構造方法 Integer(int),因爲該方法有可能通過緩存經常請求的值而顯著提高空間和時間性能 .

查看Integer的valueOf方法的:

    public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        //static final int low = -128;
        //當-128=<i<=127的時候,就直接在緩存中取出 i de  Integer 類型對象
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        //否則就在堆內存中創建
        return new Integer(i);
    }

看出對於範圍 [-128,127] 的整數,valueOf 方法做了特殊處理。採用IntegerCache.cache[i + (-IntegerCache.low)]; 這個方法。

查看 IntegerCache 類的實現爲:

    private static class IntegerCache {
        static final int low = -128; //最小值是固定的
        static final int high;
        static final Integer cache[];//cache 緩存是一個存放Integer類型的數組

        static { //初始化,最大值可以配置
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            }
            high = h;

            cache = new Integer[(high - low) + 1];  //初始化數組
            int j = low;
            //緩存區間數據
            for(int k = 0; k < cache.length; k++)
            //將-128~127包裝成256個對象存入緩存
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }

IntegerCache初始化後內存中就有Integer緩衝區cache[]了,-128~127區間的int值有其對應的的包裝對象。這就是 valueOf 方法真正的優化方法,當-128=

public class ZhuangXaing {

    public static void main(String[] args) {
        Integer i= new Integer(12);
        Integer j=12;
        Integer k=Integer.valueOf(12);


        Integer l= new Integer(232);
        Integer m=232;
        Integer n=232;

        Double  q = 232.0;

        System.out.println("use ==.......");    
        System.out.println(i==12);
        System.out.println(i==j);
        System.out.println(j==k);

        System.out.println(l==232);
        System.out.println(l==m);
        System.out.println(m==n);

        System.out.println("use equals.....");
        System.out.println(m.equals(n));
        System.out.println(m.equals(q));

    }

}

輸出結果:

use ==.......
true
false
true
true
false
false
use equals.....
true
false

Integer i= new Integer(12); 是指明瞭在堆內存中創建對象;
Integer j=12; 是自動裝箱,調用valueOf 方法,返回return IntegerCache.cache[12 + 128], 得到的是Integer 緩衝池中的對象。Integer k=Integer.valueOf(12);Integer j=12; 本質上相同,指向緩衝池中同一對象。包裝對象與數值比較,自動拆箱
而對於大於127 的數值,執行的都是return new Integer(i) 都在堆內存中,但是地址不同。

對於equals 方法比較的是數值大小:

public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

可以看出比較的 obj 如果是 Integer 的實例,則比較拆箱後數值的是否相等。否則返回false。

2,下面這段代碼輸出結果是什麼:

public class Main {
    public static void main(String[] args) {

        Double i1 = 100.0;
        Double i2 = 100.0;
        Double i3 = 200.0;
        Double i4 = 200.0;

        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
//false
//false

因爲Double類的valueOf方法會採用與Integer類的valueOf方法不同的實現。很簡單:在某個範圍內的整型數值的個數是有限的,而浮點數卻不是。

其他的包裝器:
Boolean: (全部緩存)
Byte: (全部緩存)

Character ( <=127 緩存)
Short (-128~127 緩存)
Long (-128~127 緩存)

Float (沒有緩存)
Doulbe (沒有緩存)

3,下面這段代碼輸出結果是什麼:

public class Main {
    public static void main(String[] args) {

        Boolean i1 = false;
        Boolean i2 = false;
        Boolean i3 = true;
        Boolean i4 = true;

        System.out.println(i1==i2);
        System.out.println(i3==i4);
    }
}

先看Boolean 類的源碼 ,valueOf 方法的實現:

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

而其中的 TRUE 和FALSE又是什麼呢?在Boolean中定義了2個靜態成員屬性:

public static final Boolean TRUE = new Boolean(true);

    /** 
     * The <code>Boolean</code> object corresponding to the primitive 
     * value <code>false</code>. 
     */
    public static final Boolean FALSE = new Boolean(false);

由此可知上面代碼輸出都爲true .


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章