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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 梁志仲 中级黑马   /  2012-7-26 23:49  /  1960 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 梁志仲 于 2012-7-27 15:26 编辑

class Test
{
public static void main(String[] args)
{

  String s1="aaa";
  String s2= new String("aaa");
  String s3="aaa";
  System.out.println("s1==s2::"+(s1==s2));  //false
  System.out.println("s1.equals(s2)::"+(s1.equals(s2))); //true
  System.out.println("s1==s3::"+(s1==s3));//true
  System.out.println("s1.equals(s3)::"+(s1.equals(s3)));//true
}
}

为什么直接赋值的方式s3的地址值就会等于s1,而通过new出来的s2的地址值就不相等?
s1指向的对象"aaa"已经存在,s2为什么不指向已存在的字符串对象,而s3却可以指向已存在的对象。

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

7 个回复

倒序浏览
class Test
{
public static void main(String[] args)
{

  String s1="aaa";//JVM在内存常量池中建立"aaa”对象,并使s1指向这个对象
  String s2= new String("aaa");//因为使用了new这个关键字,所以JVM会在堆内存中建立"aaa”对象,并使s2指向这个对象  String s3="aaa";//内存常量池中已有"aaa”对象,s3直接指向这个对象  System.out.println("s1==s2::"+(s1==s2));  //false
  System.out.println("s1.equals(s2)::"+(s1.equals(s2))); //true
  System.out.println("s1==s3::"+(s1==s3));//true
  System.out.println("s1.equals(s3)::"+(s1.equals(s3)));//true
}
}
回复 使用道具 举报
String s1="aaa",这个是在栈内存中创建的,当String s3="aaa"时它会先在栈中寻找"aaa"所在的地址,如果有这样的地址的话,就会指向它, 如果没有这样的地址才会开辟新的内存地址. 而因为String s2=new String("aaa");使用new的方式在堆中创建一个新的对象. 它们处于不同的内存区域当中.
回复 使用道具 举报
内存中有字符串常量池,如果不是new出来的字符串,就会放到常量池中,
以后要是再有引用变量引用相同的字符串,并不会再次创建新的字符串,而是引用常量池中已存在的字符串,
但是如果你new一个String,那么不管常量池中有没有相同的字符串,都会创建新的字符串

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
其实这个问题很简单:
你的代码中:String s1="aaa";
                   String s2=new String("aaa");
                   String s3="aaa";
在字符串中的特点是:如果使用new关键字创建的对象会在内存中开辟新的内存空间,这样就会分配新的地址值
                    而如果在字符串常量池中已经存在"aaa"字符串常量,则有没有被new的话,s3会指向已经存在的"aaa"
                                字符串常量,不会开辟新的内存空间,也不会分配新的内存地址。所以会出现你说的那种情况。
回复 使用道具 举报
1.常量池constant pool专门用于管理在编译期被确定并被保存在已编译的.class文件中的一些数据。它包括关于类。方法。接口中的变量,也包括字符串常量。
2."aaa"和new String("aaa")的区别:
当在程序中直接使用形如"aaa"的字符串直接量(包括可以在编译时就计算出来的字符串值)时,jvm使用常量池来管理这些字符串;
但使用new String("aaa")时,jvm会先使用常量池来管理"hello"直接量,再调用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。即产生了两个对象。
3.在示例代码中,s1和s3所引用的字符串在编译期就确定下来,其指向的是常量池中的同一个字符串对象。s2创建的字符串对象是在运行时创建出来的,被保存在运行时内存中。
回复 使用道具 举报
帮楼主分析一下,这个也是经常要考的面试题,字符串常量池概念是一种设计模式,貌似是享元模式。举个例子:你知道word文档不?如果你写在word文档里的内容都在内存中创建的话,很快就会出现内存泄露的,那么怎么解决这个问题呢?开发人员就想,英文不就26个字母吗?我就让你在内存里创建26个这样的小对象,你调用它们的时候只要给他们加个各自的属性就行了,这个属性就是x、y坐标。即在word文档里显示的位置是不同的。
这样理解字符串也可以很好的理解了,如果你每创建一个字符串,内存都要给你分配空间去装他们,那么当数据量很大时(处理大量字符串以后是常有的事),内存很快就会溢出。那么如何解决呢,java的开发人员想到,你存进来的字符串无非是由一些字符组成的,那么我存只存字符,并给这些字符加上角标属性(这也是为什么字符串有角标属性的原因),当你存进另外一个字符串的时候,我存只存我没有的字符,有了我就不存了。显示的时候只要按照你记住的索引位置去掉这些字符就哦了。但是你通过String s = new String("ysdf");这样的方式创建字符,我识别不了,就会直接把你作为一个字符串来处理。这里面是两个对象。
回复 使用道具 举报
王志明 发表于 2012-7-27 00:10
内存中有字符串常量池,如果不是new出来的字符串,就会放到常量池中,
以后要是再有引用变量引用相同的字符 ...

我并不同意你这个观点!字符串都是要放到常量池里的,new出来的这个字符串是在堆内存里的,它通过构造传递的值才是字符串常量池里的。所以你比较两个地址值当然不同了,因为他们所处的位置都不同。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马