为什么我们常说基本类型传递的是具体的值,而对象传递的是对象的内存地址呢。要搞清楚这个问题就要搞清楚栈内存与堆内存。
java的内存分为栈内存和堆内存,两者的作用是不同的,我们可以简单的理解如下:
当我们创建一个java基本类型的变量时,只会用到栈内存而不会用到堆内存,栈内存中所存储的内容就是基本类型的值。
int a = 3;
int b = 3;
执行第一行 int a = 3;时,JVM先会创建一个变量为a的引用,然后在栈内存中查找是否已经存在3这个值,没有找到,就会在栈内存中开辟一片区域存储3,然后将a指向存储3的位置。接着执行第二行int b=3;时也是先在栈内存中查找是否已经存在3这个值,是可以找到的,这时就将变量b的引用也指向存储3的位置。
当我们用new来创建一个非基本类型的对象时,就不仅要用到栈内存还要用到堆内存。
例如,Student s=new Student();
也会先在栈内存中开辟一块内存,用s指向这块内存,但这时栈内存存储的不是new Student(),而只是一个内存地址,这个内存地址就是在堆内存中存储new Student()的那块内存的首地址。
有了上面的概念,就可以解决一些简单的问题了。
第一个,我们都知道比较字符串的内容要用到equals(),而不是==,原因是什么呢
String s1=new String(“abc”);
String s2=new String(“abc”);
s1==s2 的结果是false,原因很简单,因为第一行和第二行都用到了new来产生新的对象,这两个对象在堆内存中的首地址肯定是不同的,那么s1所指向的栈内存中的内容与s2所指向的栈内存中的内容肯定是不同的,而==
比较的是栈内存,这时肯定是不相等的。
而equals方法我们可以理解为比较的是堆内存中的内容,由于两个堆内存中的内容都是abc,则必然是相等的。
第二个,把上面的稍微换一下
String s1=“abc”;
String s2=“abc”;
这时s1==s2,因为没有new,也就没分配堆内存,都是用的是栈内存,在执行第二行时,栈内存中已经存在了abc,则s2直接指向这个地址就可以了,所以会有s1==s2。
第三个,执行 String s1=“hello”;s1=s1+“world”的结果是怎样的呢
执行第一句时,会在栈内存中分配一块内存存储hello,执行第二句时,会分配一块新的内存存储hello world,而这时的s1指向的不再是hello的那块内存而是hello world的那块内存了。存储hello 的那块内存将会被垃圾回收器所回收。
第四个,我们常说复制基本类型时传递的是具体的值,而复制对象时传递的是对象的内存地址,这时候如果将栈内存和堆内存理解了,就可以明白是为什么了。
补充:
String a="abc";
String b="abc";
String c=new String("abc");
String d=c.intern();
因为引用变量c指向堆内存的地址;但是intern(); 却在栈中开辟了一块内存;其实c.intern(); 执行时,在栈内存中发现存在对象“abc”,所以直接将指针指向“abc”,这样 a == d, b==d 结果为true;