Java中ArrayList中存放的是值还是引用?

22 篇文章 0 订阅

首先我们将ArrayList中的泛型指定为基本数据类型的包装类和我们自定义的一个User类:

public class ArrayListTest {

    static class User {
        private String name;
        private int age;

        public User(String name , int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    public static void main(String[] args) {
        ArrayList<Integer> integerArrayList = new ArrayList<>();
        int testInt = 10;
        integerArrayList.add(testInt);
        testInt = 20;
        integerArrayList.add(testInt);
        System.out.println(integerArrayList.toString());

        ArrayList<Double> doubleArrayList = new ArrayList<>();
        double testDouble = 100.0;
        doubleArrayList.add(testDouble);
        testDouble = 200.0;
        doubleArrayList.add(testDouble);
        System.out.println(doubleArrayList.toString());

        ArrayList<User> userArrayList = new ArrayList<>();
        User testUser = new User("张三",20);
        userArrayList.add(testUser);
        testUser.age = 22;
        userArrayList.add(testUser);
        for (User user : userArrayList) {
            System.out.println(user.toString());
        }
    }

这里我们试了Integer和Double两种,看一下结果:

由此可见,修改int和double不会对之前的内容造成影响,但是修改User会对之前的内容造成影响。
所以,网友说的:“ArrayList中如果是基本数据类型,那么存放的就是值,如果是对象,那么存放的就是对象的引用而不是对象的拷贝”的说法目前看样子好像是对的,但是!!有没有注意到一个问题,就是ArrayList可以存放基本数据类型吗?我们尝试了一下,如果将泛型指定为基本数据类型就会报错,如图:

所以说,ArrayList不能存放基本数据类型,只能存放基本数据类型的包装类,也就是说存放基本数据类型的时候会自动装箱成一个对象,然后把引用存放进去。那好,就算基本数据类型存不了,存的是包装类,那么我修改了里面的内容之后,Integer和Double两次却存放了不同的值,而User修改后存放了两个相同的内容。因为如果泛型是Integer或Double的话,两次存放的是不同的对象的引用而不是一个,如果是一个的话,那当然会导致之前的内容改变咯。《Java编程思想》里面说过:无论何时,对同一个对象调用hashCode()都应该生成同样的值。所以我们来打印一下他们的hash值就可以判断是不是同一个对象。我们使用System.identityHashCode()来获取hash值:

    ……
    public static void main(String[] args) {
        ArrayList<Integer> integerArrayList = new ArrayList<>();
        int testInt = 10;
        integerArrayList.add(testInt);
        testInt = 20;
        integerArrayList.add(testInt);
        for (Integer integer : integerArrayList) {
            System.out.println(integer + " : "+ System.identityHashCode(integer));
        }
        System.out.println();

        ArrayList<Double> doubleArrayList = new ArrayList<>();
        double testDouble = 100.0;
        doubleArrayList.add(testDouble);
        testDouble = 200.0;
        doubleArrayList.add(testDouble);
        for (Double aDouble : doubleArrayList) {
            System.out.println(aDouble + " : "+ System.identityHashCode(aDouble));
        }

        ArrayList<User> userArrayList = new ArrayList<>();
        User testUser = new User("张三",20);
        System.out.println("\nUser修改前:");
        System.out.println(testUser.toString());
        System.out.println(System.identityHashCode(testUser));
        userArrayList.add(testUser);
        testUser.age = 22;
        System.out.println("User修改后:");
        System.out.println(testUser.toString());
        System.out.println(System.identityHashCode(testUser));
        userArrayList.add(testUser);
        System.out.println("\n遍历ArrayList<User>:");
        for (User user : userArrayList) {
            System.out.println(user.toString());
            System.out.println(System.identityHashCode(user));
        }

    }
    ……

打印的结果如下:

 从打印的结果可以看出,Integer和Double并不是修改内容,而是存了一个新的对象的引用进去,所以存放基本数据类型的包装类也是引用并非是值,而User对象修改后却可以影响到之前已经存储的内容,两个User是同一个。

为什么Integer和Double修改不了呢?因为他们都属于不可变量,都是final修饰的,也就是说第二次赋值的时候指向的是一个新的对象,而不是修改之前的内容。从源码中我们可以看到:

 可以看到,基本数据类型的包装类和String一样都是final修饰的,而且Double和Integer等基本数据类型包装类中也没有提供修改值的方法,也就是说之前看样子是在修改数据,其实是指向了一个新的内存地址,ArrayList中第二次存放数据的时候,并没有改变第一次存放的引用中的内存地址中的值,而是存了一个新的引用。

结论

那么到现在为止,就可以得出一个结论了: ArrayList中存放的是引用而不是值

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值