论坛首页 Java企业应用论坛

String到底创建多少个对象及相不相等等问题的汇总

浏览 15222 次
该帖已经被评为精华帖
作者 正文
   发表时间:2012-04-09   最后修改:2012-04-29

 

冒着被投新手帖的风险做个汇总。不要再争论String到底创建多少个对象及相不相等的问题了,好好学习下java语言规范和java虚拟机规范才是真理吧。规范上写的很明白

 

此处只考虑HotSpot,其他的没用过。

 

String s1 = new String("xyz"); 到底创建几个要看虚拟机的实现。而且要联系上下文

1、假设:HotSpot1.6

之前没有创建过xyz 则创建2个,之前创建过“xyz”则只创建1个

2、假设:HotSpot1.7

之前没有创建过xyz 则创建2个,之前创建过“xyz”则只创建1个

为什么请参考下边的问题2

 

 

String s3 = s1 + s2; 
System.out.println(s3.intern() == s3);
 到底不相等 要看虚拟机的实现

1、假设:hotspot1.6

则false不相等

2、假设:hotspot1.7

假设在之前常量池中没有“abcabc”时,true相等

为什么请参考下边的问题2和3

 

《深入Java虚拟机(原书第二版)》(基于JDK2)

即如果池中没有 需要将new一个副本放入常量池,因此在之前没有创建过时,将产生两个对象

 

 

Java虚拟机规范(Java SE 7)

Java 语言需要全局统一的字符常量(这就意味着如果不同字面量(Literal)包含着相
同的码点序列,就必须引用着相同的 String 类的实例(JLS §3.10.5)) 。此外,在任意
字符串上调用 String.intern 方法,如果那个字符串是字面量的话,方法的结果应当是对
相同字面量的 String 实例的引用。因此, 
("a" + "b" + "c").intern() == "abc" 
必须返回 true。 
为了得到字符常量,Java 虚拟机需要检查 CONSTANT_String_info 结构中的码点序
列。 
 如果 String.intern 方法以前曾经被某个与 CONSTANT_String_info 结构中的码
点序列一样的 String 实例调用过,那么此次字符常量获取的结果将是一个指向相同
String 实例的引用。 
 否则,一个新的 String 实例会被创建,它会包含着指定 CONSTANT_String_info
结构中 Unicode 码点序列;字符常量获取的结果是指向那个新 String 实例的引用。
最后,新 String 实例的 intern 方法被 Java 虚拟机自动调用。

 字符常量获取的结果是指向那个新 String 实例的引用:因此 调用s3.intern() 在之前没有创建过abcabc时 总共就产生一个实例

 

测试用例:

     //oracle hotspot1.7执行(Java(TM) SE Runtime Environment (build 1.7.0-b147))
     public static void testForHotSpot7() {
        String s1 = "abc";  
        String s2 = "abc";  
        String s3 = s1 + s2;
        String s4 = s1 + s2;
        String s5 = new String("xyz");//之前没有创建过,则创建两个对象,一个在堆中,一个在PermGen的常量池
        System.out.println(s3.intern() == s3);//true  
        System.out.println(s3.intern() == s4);//false
     
     }
      //oracle hotspot1.6执行(Java(TM) SE Runtime Environment (build 1.6.0_29-b11))
     public static void testForHotSpot6() {
        String s1 = "abc";  
        String s2 = "abc";  
        String s3 = s1 + s2;
        String s4 = s1 + s2;
        System.out.println(s3.intern() == s3);//false 
        System.out.println(s3.intern() == s4);//false

        String s5 = new String("xyz");//之前没有创建过,则创建两个对象 一个在堆 一个在PermGen常量池
     }

       具体为什么请参考问题2和问题3


这种问题本身我觉得在没有假设前提的情况下是没有意义的。。


1、问题:请别再拿“String s = new String("xyz");创建了多少个String实例”来面试了吧

Java代码 
String s = new String("xyz"); 

创建了几个String Object?

请别再拿“String s = new String("xyz");创建了多少个String实例”来面试了吧



2、问题:发现String#intern的API描述有问题

在我写下此贴之前我的测试环境仅限于xp上的hotspot(打印false),看了下回复,才发现JRockit打印了true。
那么对于这样一个简单的程序,有的jvm打印true,有的打印false,究竟谁,是有bug的版本,按我下文的论述,个人觉得打印false才是正确的。

RednaxelaFX的回复  http://www.iteye.com/topic/1112592?page=3#2216483


3、Java String 详解 - String Literal

String s1 = "abc"; 
String s2 = "abc"; 
String s3 = s1 + s2; 
System.out.println(s3.intern() == s3);

 结果为什么?

http://www.iteye.com/topic/1122514#2337728


不要再讨论这种问题了,好好学习下java语言规范和java虚拟机规范 自然就明白了! 规范上写的大家一般都是遵守的,规范上没有的大家是可以乱来的。规范上写的很明白.

 

推荐阅读:http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html

JavaSE7 javadoc  http://docs.oracle.com/javase/7/docs/api/

Java语言和虚拟机规范 http://docs.oracle.com/javase/specs/index.html

  • 大小: 114.5 KB
   发表时间:2012-04-09  
此贴即将成为口水贴
0 请登录后投票
   发表时间:2012-04-09  
freish 写道
此贴即将成为口水贴

完了 我肯定是找骂 哈哈哈 就这样吧 
0 请登录后投票
   发表时间:2012-04-09  
楼主最近发帖热情很高嘛!
0 请登录后投票
   发表时间:2012-04-09   最后修改:2012-04-09
guofengcn 写道
楼主最近发帖热情很高嘛!

有点空闲时间就发发贴 哈哈  其实我发了一篇不该发的帖子,发完后怕了
0 请登录后投票
   发表时间:2012-04-09  
这东西弄的头晕
0 请登录后投票
   发表时间:2012-04-09  
话说,这题确实是每个公司必面题~
0 请登录后投票
   发表时间:2012-04-09  
还是支持一下吧。
好多看似简单的问题实际上很难说清楚,还是自己水平不够。
继续学习去。
0 请登录后投票
   发表时间:2012-04-09  
caoxudong818 写道
还是支持一下吧。
好多看似简单的问题实际上很难说清楚,还是自己水平不够。
继续学习去。


我又补充了一下测试用例  ,做个汇总贴 希望对大家有用
0 请登录后投票
   发表时间:2012-04-09  
freish 写道
此贴即将成为口水贴

我又补充了测试用例,呵呵,口水就口水吧
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics