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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© dev 中级黑马   /  2012-7-3 18:44  /  2199 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 翁游龙 于 2012-7-4 16:04 编辑

第一次见到这样奇怪的问题,以下有两个类StringJoinTest和StringJoinTest02,
程序如下:


类StringJoinTest:


public class StringJoinTest{
        public static void main(String[] args){
                String s1 = "HeimaJava";
                String s2 = "Heima" + "Java";
                System.out.println(s1 == s2); //true


                //定义两个字符串
                String str1 = "Heima";
                String str2 = "Java";
                //将str1和str2进行连接运算
                String s3 = str1 + str2;
                System.out.println(s1 == s3);  //false
        }
}


类StringJoinTest02:


public class StringJoinTest02{
        public static void main(String[] args){
                String s1 = "HeimaJava";
                String s2 = "Heima" + "Java";
                System.out.println(s1 == s2); //true


                //定义两个字符串
                final String str1 = "Heima";
                final String str2 = "Java";
                //将str1和str2进行连接运算
                String s3 = str1 + str2;
                System.out.println(s1 == s3);  //true
        }
}


问题:两个类中同样是比较s1和s3的地址池,为什么使用了final修饰后的字符串
判断打印的是结果为true呢?


评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 这个问题,确实比较给力!赞一个!.

查看全部评分

6 个回复

倒序浏览
因为第一个类中的str1和str2是一个引用指向字符串常量池里,它是在编译时期就这么做的,但是String s3 = str1 + str2;中的s3是要在运行时才能知道结果,所以在s3得到结果之前str1和str2什么时候赋值是不知道的,就相当于二个变量,所以str1+str2是在堆内存中创建的,那么s3是不可能把向字符串常量池的,所以s1==s2是false。第二个类中str1和str2被final修饰就是说,他们不可再变,再说因为"Heima"和"java"都是常量,所以str1和str2的值在编译时期就确定了,并存在于字符串常量 池里,在常量池里虚拟机会自动找到它们连接后的值,并把引用指向s3,所以s1和s3引用指向的地址是相同的,所以s1==s3是true

评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1 赞一个!

查看全部评分

回复 使用道具 举报
feigecal 发表于 2012-7-3 20:25
因为第一个类中的str1和str2是一个引用指向字符串常量池里,它是在编译时期就这么做的,但是String s3 = st ...

说的很不错!学习了!
回复 使用道具 举报
韦念欣 发表于 2012-7-3 21:14
说的很不错!学习了!

一起努力吧,呵呵
回复 使用道具 举报
其实你i想理解的话我给你讲个final的作用你就知道了,首先你前一段String s1 = "HeimaJava";
                 String s2 = "Heima" + "Java";
                 System.out.println(s1 == s2); //true 这个打印为true的原因很明显,因为heima 和java都是字符串常量池当中的数据,你这样写的效果跟直接这样写String strs2="HeimaJava"是一样的效果,所以打印结果为true,但是第二个因为+运算符会在内存重新创建一个对象,然后将引用赋给s2所以两个的地址不相同 所以打印为false
final的作用指的是引用变量不可变,而不是引用变量的内容不可变,就好像你定义一个Stringbuffer对象为final类型 final StringBuffer str = new StringBuffer("123"); 执行以下语句会报错  str = new StringBuffer(""); 但是a.append("aff");就不会报错,这就说明这个final修饰变量只是引用不能变,但这个题目有一点不一样,String 类型本身就是不可变的,就好像你定义一个变量String  s1 = "abc"这里面s1指向的内容是不会改变的 你只能改变s1的引用地址,但是这道题你将String定义成了fianl类型 两者都不能变,所以相加就是两个常量再相加,所以会返回true
回复 使用道具 举报
我的理解是这样的,不知道对不对:
查看String文档有这么一句:Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。
所以很好理解第一个类中的s3实际是在堆内存中开辟了新的对象,而s1的引用地址是指向字符串常量池的,结果为(s1==s3)false

第二个类的str1和str2被final修饰",在常量池就会开辟两块空间存放“Heima”和“Java”,那么串联时因为被final修饰了(引用地址不可改变),所以不会在堆内存中开辟新的空间,而是在常量池中查找,找到“HeimaJava”后把常量池存“HeimaJava”的地址(这个地址指向s1)仍给s3,结果(s1==s3)true

评分

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

查看全部评分

回复 使用道具 举报
dev 中级黑马 2012-7-4 16:03:28
7#
feigecal 发表于 2012-7-3 20:25
因为第一个类中的str1和str2是一个引用指向字符串常量池里,它是在编译时期就这么做的,但是String s3 = st ...

嗯。我明白了。谢谢你。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马