1. 程式人生 > >Interger是值傳遞還是地址(引用)傳遞?

Interger是值傳遞還是地址(引用)傳遞?

首先,放一句話。引用型別都是傳遞引用。但是對於Integer這種包裝型別來說,可能會讓人產生誤區,比如看下面程式碼片段:

        Integer i = new Integer(1);
        Integer j = i;
        System.out.println(j);
        i = 2;
        System.out.println(j);
        System.out.println(i);

j的輸出結果都是1,i的輸出結果最後是2。

這是因為i這個引用指向的物件改變了,i=2這條語句你可以看成i=new Integer(2),而不是修改i最開始所指向的物件的值,這個值也不能改變。因為在Integer內部也是封裝了一個final修飾的int型別的值,這裡和String型別大同小異。也就是說包裝類和String型別一樣的,不可以改變這個包裝類的例項的值,我們對包裝類的賦值操作實際上是建立了一個新的物件,然後把這個物件交給這個引用去管理,因為包裝類的自動拆箱和裝箱,所以看起來這個操作和基本型別的賦值差不多,但是這裡確確實實是建立了一個新的物件。下面語句是包裝類中找到的一行程式碼:

    private final int value;

那麼,如何證明包裝類確實是採用的地址傳遞呢?我們可以採用synchronize這個關鍵字來證明,具體思路如下:兩個執行緒對同一個數字進行自增操作,如果自增到一定大小時停止自增,並且輸出每次自增後的值。如果不使用synchronize這個關鍵字,那麼輸出的值可能會出現一些預料不到的情況,比如下面程式碼:

class Test {
    public static void main(String[] args) {
        Thread t1 = new Thread(new A());
        Thread t2 = new Thread(new A());
        t1.start();
        t2.start();
    }
}

class A implements Runnable {
    static Integer a = 100;
    static int val = 0;

    @Override
    public void run() {
        while (val < 100) {
            val++;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(val);
        }
    }
}

部分執行結果:

 

如果使用synchronize關鍵字,確保傳入的monitor是同一個物件,那麼執行緒執行的時候將會一切正常。要想確保傳入的是同一個物件,那麼肯定只能使用地址傳遞的物件才可以。因此,我們把Integer的物件作為這個monitor,具體程式碼如下:

class Test {
    public static void main(String[] args) {
        Thread t1 = new Thread(new A());
        Thread t2 = new Thread(new A());
        t1.start();
        t2.start();
    }
}

class A implements Runnable {
    static Integer a = 100;
    static int val = 0;

    @Override
    public void run() {
        synchronized (a) {
            while (val < 100) {
                val++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(val);
            }
        }
    }
}

最後執行結果和預想的一樣,從1到一百挨著輸出,沒有重複,也沒有漏掉某些值的輸出。所以證明了傳入的是同一個物件,既然是同一個物件,那麼肯定就是地址傳遞了。