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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 不胖的胖子 中级黑马   /  2013-5-29 18:11  /  2394 人查看  /  13 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 不胖的胖子 于 2013-5-30 11:35 编辑

1,问题最早的来源
    那天在20届交流区,看到一兄弟问一个字符串的问题,刚开始以为很简单。
最后仔细看时,才发现问题很大。来看下那位兄弟的代码:
  1. public class StringTest
  2. {
  3.         public static void main(String[] args) {            
  4.                 String s1 = "a";            
  5.                 String s2 = s1 + "b";           
  6.                 String s3 = "a" + "b";               
  7.                 System.out.println(s2 == "ab");               
  8.                 System.out.println(s3 == "ab");              
  9.                 System.out.println(s2.equals(s3));               
  10.                 System.out.println(s2 == s3);   
  11.                
  12.         }
  13. }
复制代码
再来看看输出结果:
  1. ---------- 运行java程序 ----------
  2. false
  3. true
  4. true
  5. false

  6. 输出完成 (耗时 0 秒) - 正常终止
复制代码
2,我的问题
我清楚的知道,s2 s3 的字符串字面值都是"ab",通过 == 其实想比较的是它们是否指向同一对象。
s2.equals(s3)---->比较字符串内容,返回true 没问题
s2 == s3 ---->比较它们是否为同一对象,返回false。
我从资料中查到的,+ += 这两个操作符被String唯一重载了。(java是不允许程序员重载操作符的)
s3= "a" + "b"; 这一句实际是调用StringBuilder的append方法将两个字符串连接的。s3最后和 "ab"  == 比较表明指向同一对象
s2= s1 + "b"; 这一句完成后 s2 字符串内容也是"ab",同样是用StringBuilder连接。 s2 最后 和 "ab" == 比较表明不是同一对象

我的疑问就是:在使用 + 操作符操作字符串时,是否参与的只有字符串常量时才不会新建空间产生对象(对应s3这种情况)
  s2 = s1 + "b" 中有引用变量 s1,这是否是导致 s2 == s3 --->false 的原因了??
希望大家能帮下忙

3  个人了解到的一些
   上次有一位兄弟问道:
   String s1 = "abc"; ---> 内存中一个对象
   String s2 = new String("abc"); --->内存中两个对象
为什么?
当时也没有弄明白。
今天把老毕视频又找出来看了看,他强调的是知道如何操作字符串(StringAPI各种方法)。并没有解释太多。
最后看了下API,关于构造方法 String(String original)。
当我们传入参数 "abc" 这就已经在内存中产生一个对象了。再使用关键字 new 新建对象,其实是 "abc"的一个副本,但是还是会新建空间创建对象。

参考书目: Core Java(卷一) (8版) Thinking in Java(4版)  Java编程语言(3版)  Java疯狂讲义(不知道哪版)





评分

参与人数 1技术分 +2 收起 理由
袁梦希 + 2 胖子不容易给你2分

查看全部评分

13 个回复

倒序浏览

前提是字符串是常量,一经创建不能修改。“a” 是一个对象

如果是这样:
String s1 = "a";
String s2 = "a";
s1 == s2 ;得到的结果是true。因为“a”这个对象字符串池中是有的,直接拿来使用就可以了
我可以回答你这个问题:

String s1 = "a";这个地方因为字符串池中没有“a”这个对象,所以直接创建了一个对象,并且将引用赋值给了s1.

对象用 == 判断的时候,基本都是false。因为持有的this引用不同。也就是开辟的空间不同

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 赞一个!

查看全部评分

回复 使用道具 举报
Super_Class 发表于 2013-5-29 18:28
前提是字符串是常量,一经创建不能修改。“a” 是一个对象

如果是这样:

哥  谢谢你 !!
我的问题的关键是 + 操作符重载时发生了什么
几本书上面我都看过讲解String这块的
都没怎么提这个问题。最多说String是不变的
==  和 equals 的区别 或者是StringBuilder 可能是我看的不仔细吧 还是谢谢你!!
回复 使用道具 举报
s2 = s1 +"b";这个得到的对象“ab”不是从字符串常量池中得到的。


如果使用intern() 方法:

s2 = (s1+"b").intern();

先让这个对象到字符串池中找。如果找不到就创建一个。如果找到了就直接拿来用。

你应该就可以理解了
回复 使用道具 举报
哥们的问题确实很深层次啊,我也一直对老师讲的两对象的问题有点疑惑,不知道在内存中是怎么个存法,老师也没多作解释
至于哥们讲的StringBuilder连接,俺就更不懂了,哪天哥们想明白了,不妨说说哈
回复 使用道具 举报
个人理解:
String 其实是一个一维数组,
打个比方 Object[] obj 是一个一维的 Object 数组, 意味着 obj 这个变量 存的都是 Object类的 对象的应用,或者说是对象的地址值。
同理 String s2 = s1 + "b" 就意味着 s2 数组存放的是 s1 的地址值和 "b" 对象的地址值
     String s3 = "a" + "b" 存放的就是 "a" 的地址值 和 "b" 的地址值
因此 s2 这个对象与 "ab" 对象 存放的数值是不一样的 会创建新对象。
er s3 对象存放的数值与 "ab" 是一样的 所以 指向的是常量池 中的对象

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 哥们疯了啥都会

查看全部评分

回复 使用道具 举报
神之梦 发表于 2013-5-29 18:48
哥们的问题确实很深层次啊,我也一直对老师讲的两对象的问题有点疑惑,不知道在内存中是怎么个存法,老师也 ...

最近太忙了
其实很多问题 我们都是一知半解
泛型  类加载器
反射(算是比较容易掌握用法的)
JVM
23种设计模式
异常(这块很枯燥)
垃圾回收
  实在是没时间去研究 每天睡5个小时
论文还没改完   我是真的很想去黑马 这样就有时间潜心去弄懂这些东西了
回复 使用道具 举报
First 发表于 2013-5-29 19:07
个人理解:
String 其实是一个一维数组,
打个比方 Object[] obj 是一个一维的 Object 数组, 意味着 obj 这 ...

我尝试过源代码 还是没坚持看下去  
如果有机会进黑马 要好好研究下
这些东西 谢谢你兄弟
我会综合你们的答案再试着去理解下  
回复 使用道具 举报
First 中级黑马 2013-5-29 23:44:30
9#
加油加油--{:soso_e182:}
回复 使用道具 举报
First 发表于 2013-5-29 23:44
加油加油--

谢谢兄弟啊!!!
正在努力中啊!!
回复 使用道具 举报
First 发表于 2013-5-29 23:44
加油加油--

谢谢兄弟啊!!!
正在努力中啊!!
回复 使用道具 举报
不胖的胖子 发表于 2013-5-29 18:39
哥  谢谢你 !!
我的问题的关键是 + 操作符重载时发生了什么
几本书上面我都看过讲解String这块的

当使用“+”运算符链接字符串时,如果链接的是两个字符串常量,那么引用变量指向的是由这两个直接量连接成的字符串常量池中的一个字符串对象,如果参与链接的包含变量,那么内存中将会新建一个这个变量指向的字符串对象的一个副本,再合成一个新的字符串对象
String a ="a"+"b";//运行字符串常量池中会缓存一个"ab"的字符串
String b = a+"c";//内存中会创建一个新的字符串对象,该对象由一个a变量指向的字符串的副本和直接量"c"组成

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
楼主你好,如果帖子没问题了,那么请把帖子的类型改为“已解决”。如果不会改,请看我的个性签名
回复 使用道具 举报
这个问题是很好的问题,面试的时候也会经常遇到。

首先要明确四点:
|--变量
|--常量
|--编译
|--常量地址


字符串常量是一个特殊的常量,如果在一开始创建了一个"a",那么这个"a"会存储到常量池中,那么再用"a"时,就会自动到常量池中去找有没有"a",如果有,就直接用,没有就创建。

对于变量,s1虽然代表的是"a",但是在编译时,java虚拟机不会通过变量再去判断是否存在该变量对应的值,检测到变量就会重新创建一个新的常量,所以第一个得到的结果是false。

最后一点,常量之地址,对于上面的"a",会有一个地址对应,"b"也有,通过常量运算,"a"+"b",这样得到的地址是"a"的地址,和"ab"的地址一样,也是"a"的地址。有人会问:"a"是"a"的地址,"ab"是"ab"的地址,怎么一样呢?这就和字符串的原理有关,字符串实质是由每一个字符组成的,在内存中读到的是字符连续起来的结果,字符串对应的地址就是首个字符的地址。

这是完整解答,希望有帮助!


回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马