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到一百挨着输出,没有重复,也没有漏掉某些值的输出。所以证明了传入的是同一个对象,既然是同一个对象,那么肯定就是地址传递了。

猜你喜欢

转载自blog.csdn.net/qq_25864827/article/details/84751337
今日推荐