最近遇到一个线上问题,原因是忽略的引用的一些语法,导致出错,现在记录一下:
@Testpublic 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字符串,却不是这样的
@Testpublic void testString(){String a = "1";String b = a;b += "2";System.out.println(a);//1System.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的存储位置: