A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 001可望成功 中级黑马   /  2014-7-12 14:41  /  3150 人查看  /  19 人回复  /   5 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 001可望成功 于 2014-7-14 10:39 编辑

这几天看到有些小伙伴问这方面的问题
例如①:
int x=1;
Integer y = 1;
Integer z = new Integer(1);
System.out.println(x==y);
System.out.println(x==z);
System.out.println(y==z);
得到的结果:
true
true
flase
例如②:
String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = str1 + str2;
String str5 = new String("ab");
System.out.println(str5.equals(str3));
System.out.println(str5 == str3);
System.out.println(str5.intern() == str3);
System.out.println(str5.intern() == str4);
得到的结果:
true
false
true
false
下面就先说一下堆、栈、常量池:
  在java的内存中主要分为四个部分:栈,堆,数据区(有人说这就是常量池),代码段(存放所有的方法,被线程共享,对象被实例化的时候,都有自己的成员变量,而成员方法是共享的)
  • 栈:存放所有的基本类型变量和对象的引用变量。(注意,栈里的数据不是共享的,int a = 3;3存在a的那块内存里,int b = 3,这里会开辟出一个b的内存,存放b的3。)
  • 堆:存放所有由new产生的对象或数组,
  • 常量池:虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。说白了,就是存放基本类型常量和字符串常量的。对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的,对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。
  • 主要用于String和8大基本数据类型(这8个里Float和Double没有用到常量池)的包装类Integer,Long,Short,Character,Byte,Booleans.(包装类的数据范围是-128~127,超过了这个范围,就会在堆中新建这个对象,并不会把这对象存在常量池中了,所以,Integer o = 128;Integer i= 128;o就不等于i了)
接下来说一下上面的各种情况:

int i = 1;基本数据类型的值就存在栈中开辟的内存里,所以,基本数据 类型只在栈中开辟一块内存

Integer i2 = 1;他将基本数据类型自动装箱变为了引用数据类型,这里的1也被存到了常量池中了,他在存之前会先检测一下常量池中有没有1这块内存,如果已经开辟过这块内存了,那么,JVM直接将这块内存的地址赋给i2,如果没有的话,则开辟一块新内存存放1。既然是引用数据类型,那i2就是一个地址了,指向常量池中的某块内存,这是就以有人问了,既然i2是一个地址,那判断i==i2是不就输出false了吗?其实不是这样的,我们平时使用==判断的时候都是相同的数据类型,而这里i是一个基本数据类型,i2是一个引用数据类型,这是JVM会先将Integer拆箱转换为基本数据类型,即int i2 = 1;然后在进行比较,这样i和i2不就一样了嘛

Integer i3 = new Integer(1);一看是new,那他肯定是在堆中强制性的开辟一块内存了,不管堆内存中有没有1这块内存都会开辟。

String i4 = “abc”;这里的i4和i可就不一样了,他不是基本数据类型,而是一个引用数据类型,对于String他比较特殊,因为他也实现了常量池,所以这里的abc也被存到了常量池里了。

String i5 = new String(“abc”);既然new了,那肯定是存在堆内存中了,但是这里有个小陷阱:记得看过一个面试题,他问String i5 = new String(“abc”);是开辟了一块内存还是两块,这里你不管回答一块还是两块都不一定对,因为new String()他会强制性的在堆内存中开辟一块内存,“abc”他也是一个对象啊,JVM会现在常量池中找有没有abc这样的字符串,如果有,直接将这个对象拷贝到堆内存中,这样之开辟一快内存,如果没有,在常量池中新建这个对象,这样的话,开辟两块内存

特别注意的是:常量池是在编译的时候开辟内存,堆是在运行的时候开辟内存

String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = str1 + str2;
String str5 = "a"+"b";
System.out.println(str3==str4);
System.out.println(str3==(str1+str2));
System.out.println(str3==str5);
System.out.println(str3=="a"+"b");
得到的结果是:
false
false
true
true

字符串进行相加的时候,如果都是静态字符串,如“a”+“b”,那么组合起来的字符串存放在常量池中,在存之前先会在常量池中查找,这里不多说;如果字符串相加的时候其中有变量,如str1+“a”,str1+str2等,这样JVM会在堆内存中新建一个对象,并不会在常量池中存放。

下面时候一下String里的intern()方法,这是上面的例子:
String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = str1 + str2;
String str5 = new String("ab");
System.out.println(str5.equals(str3));
System.out.println(str5 == str3);
System.out.println(str5.intern() == str3);
System.out.println(str5.intern() == str4);
得到的结果:
true
false
true
false

在调用str5.intern()方法的时候,这个方法会首先检查字符串池中是否有str5这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用。

上面的前两个不多说,第三个str5.intern()会先在常量池中查找str5,这里返回了一个引用,就是str3,所以相等

第四个str5.intern()返回的引用是str3,str4是由两个变量组合起来的,上面已经说过,他是在堆内存中开辟的内存,不存放在常量池里,所以两个不相等。


参考资料:
对java中int和Integer的理解  http://blog.sina.com.cn/s/blog_7f033dcf01017ljx.html
java内存分析全面解析  http://blog.csdn.net/shimiso/article/details/8595564
java中的堆、栈、常量池  http://blog.csdn.net/config_man/article/details/5192059
java string = new string 内存分配问题 字符串常量池栈 堆 http://baidongxu.blog.163.com/blog/static/1747323522011924142226/





点评

额,栈数据是共享的从何说起?如果指多线程,栈是独立的,堆才是共享的。数据区和代码段是C的说法,Java里是方法区和包含在方法区中的常量池  发表于 2014-7-13 00:23

评分

参与人数 1技术分 +2 收起 理由
淡夜清风 + 2 很给力!

查看全部评分

19 个回复

倒序浏览
讲的号仔细  值得收藏
回复 使用道具 举报
顶起!!!
回复 使用道具 举报
学习了  
回复 使用道具 举报
:handshake
回复 使用道具 举报
lz讲的很详细,学习了
回复 使用道具 举报
好牛啊!顶起
回复 使用道具 举报
呵呵,不错,受教了
回复 使用道具 举报
受教了
回复 使用道具 举报
牛人遍天下           
回复 使用道具 举报
讲得好,学习
回复 使用道具 举报
不错的整理,收下了,谢咯
回复 使用道具 举报
学习了,讲的很透彻。
回复 使用道具 举报
本帖最后由 001可望成功 于 2014-7-14 10:40 编辑

评论说的很正确,那里有点误导大家了

对于数据区这个,看《java开发实践经典》上是这么写的,这块不是很清楚了,但是看网上的资料,有的人说他就是常量池,

回复 使用道具 举报
收藏了 谢谢
回复 使用道具 举报
谢谢分享
回复 使用道具 举报
看来帮助了很多的小伙伴啊,谢谢大家的支持
回复 使用道具 举报
恩,说得好详细,受教了,顶一个!
回复 使用道具 举报
说的很详细!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马