对象引用 String引用 基本类型引用 差别

本文通过具体示例探讨了Java中对象与引用的区别,解释了为何直接赋值引用会导致对象变化,并对比了String类型的特殊行为。此外,还深入解析了String常量池与堆内存中的对象存储机制。

最近遇到一个线上问题,原因是忽略的引用的一些语法,导致出错,现在记录一下:

@Test
    public void testList(){

        List<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.add("3");

        List<String> list2 = new ArrayList<String>();
        list2.add("1");
        list2.add("2");

        //我现在想获得一个新list,内容是list中有,但list2中没有的
        //于是我用了下面的代码实现
        List<String> list1 = list;
        list1.removeAll(list2);
        System.out.println(list);//[3]---看这个,原始的list也变了
        System.out.println(list1);//[3]
        System.out.println(list2);//[1, 2]
        //很明显,这里原始list的结果,并不是我想要的,我并不想让list发生变化
        //但由于我是直接将list的引用给了list1,其实这个时候list1和list是指向同一个对象的,所以对list1做操作,list也会发生变化,因为这两个压根就是一个东西

        //做个比喻,list就是一个人,他的名字叫list,他有三颗糖,分别1号,2号,3号
        //那么同时list2就是另外一个人,他的名字叫list2,他有两颗糖,分别1号,2号
        //我想要的,是获得list有,list2却没有的糖,我采用了排除法
        //但我做的操作却是:List<String> list1 = list;
        //这个相当于给list另外起了个外号,叫list1,但还是同一个人
        //所以我拿走list1的糖,其实也就是拿走了list的糖,因为就是一个人
    }

这个问题,对于自定义对象一样,只给引用,再操作那个新的引用,其实操作的都是一个对象,但是,对于String字符串,却不是这样的

 @Test
    public void testString(){
        String a = "1";
        String b = a;
        b += "2";
        System.out.println(a);//1
        System.out.println(b);//12
        //看这个操作,照样是引用,但a却没有因为b的改变
    }

扩展总结:
基本类型对象存放在栈中,
引用类型对象数据存放在堆中,
String类型数据存在堆中,但可能存两份,看下面代码

        String a = new String("good");
        String b = "good";
        String c = new String("good");
        System.out.println(a == b);
        System.out.println(a.equals(b));
        System.out.println(b == c);

第一行:首先在String常量池中查找有没有字符常量“good”.因为没有所以创建“good”对象,当执行new String(“good”)时,则在Java的堆中创建一个”good”对象,而a是该对象的引用,因此共计创建2个对象,都在堆中,一个在常量池内,一个在常量池外,两个good虽然是两个对象,但却占一块内存,都在堆中,只不过是常量池外的good指向常量池中的goog,a引用指的是常量池外的good

第二行:首先在String常量池中查找有没有字符串常量“good”,有则直接将b作为String常量池中“good”的一个引用,当你重新声明一个String型变量为“good”时,将使用串池里原来的那个“good”,而不用重新分配内存,也就是说,str与str1将会指向同一块内存,因此,此时没有创建任何对象。

第三行:依次在String常量池中查找有没有字符串常量“good”,有则不进行再次创建,由于这里用了new关键字(有new就有对象),所以在Java堆中又创建了一个“good”对象(地址与第一句在堆中创建的地址不同),而c则是这个对象的引用,因此执行此句时,创建了1个对象。

下图是a,b,c,good,list,list1,list2的存储位置:
引用图例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值