posts - 30,  comments - 28,  trackbacks - 0

自己想的一道题,算是30%原创吧 
String a=new String("Hello");
  a+="World";

 问:a的内容最后是什么?
         这两个语句,共生成了几个Java对象?

简单不?看样子非常简单吧,呵呵。
第一问:a(确切地说a引用的内容)是HelloWorld
 
第二问: 两个语句,一共生成了几个对象?
    看第一个语句,说实话,用这种方式初始化String,实在是代码垃圾。这先不管啦。这个语句是老生长谈,一个或两个对象。
    为何?第一次执行时创建了二个, 一个为字面量"Hello"(它本身是一个String对象), 一个为new String("Hello")(它是通过new创建的, 功能上和字面量"foo"完全一样, 但却是另一个对象).

第二次执行时, 只创建一个, 即new String("Hello"), 这是因为: "Hello"作为String字面量, 是存在于String Pool里面的, 第二次使用它时, 直接指向原有的String, 而不再创建新的String; 但new String("Hello")却每执行一次都创建一个新的,完全一样的String对象.

   第二个语句呢?
     3个对象。
     首先是“World”,毋庸质疑。
     那么然后呢?注意了,String是final类,不可改变。平时我们写Java会有个错觉,stringA+stringB就以为是前者尾巴接上后者脑袋。的确,在C/C++里就是如此。一点儿错都没有。
    但是Java不是,Java设计者为了更多方面的考虑,他们把String设计成了final。
    看一下JVM汇编指令吧
  0: aload_0
   1: invokespecial #1; //Method java/lang/Object."<init>":()V
   4: return

static void inti();
  Code:
   0: new #2; //class java/lang/String
   3: dup
   4: ldc #3; //String Hello
   6: invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
   9: astore_0
   10: new #5; //class java/lang/StringBuilder
   13: dup
   14: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
   17: aload_0
   18: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   21: ldc #3; //String Hello
   23: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   26: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   29: astore_0
   30: return

}

仔细看一下我做的标记,JVM给我们生成了一个StringBuilder类。(我用的是JDK5,旧版本是StringBuffer类,单单这一点小改动就能让Java的速度提高很多)。让后用append方法载入Hello和World两个String的引用(明确地说转化成字符数组)。
当载入完成后,StringBuilder实例调用toString,生成一个新的String实例(暂时称为TempString)。
 最后把引用a指向TempString


总结:两句语句总共生成了4个或5个Java类实例

PS:Java中没有指针实在是太不方便了。特别是在操作原始数据类型的时候。个人认为Java应该在这点上学学C#。指针不是洪水猛兽,对优秀程序员而言,指针是编程中的一种享受。
        希望“海豚”(Java7)能出现指针吧---很不现实,还是等开源后的Java版本吧


posted on 2006-08-14 03:18 murainwood 阅读(493) 评论(4)  编辑  收藏 所属分类: Java读书笔记


FeedBack:
# re: 继续巩固Java基础,一道综合题
2006-09-19 21:19 | Winnie
String a=new String("Hello");
a+="World";
总结:两句语句总共生成了4个或5个Java类实例

你好,看了你的结论我有些不明白,是否可以指教一二?
最近正巧在看关于Java字面量方面的内容,看过来的总结就是Java的字面量可以理解为Java的常量,而String类型的字面量呢,是保存于字符串缓冲池中的,所以我觉得就上面的代码而言,如果我们只讨论它执行一次生成几个String类实例,你在文中提到“第一次执行时创建了二个, 一个为字面量"Hello"(它本身是一个String对象), 一个为new String("Hello")”我的理解是:第一个语句生成了一个String类的实例,而且同时有一个引用变量a指向该String实例,而第二个语句才在字面量缓冲池中生成了一个helloworld和world的实例,此时引用变量a指向helloworld字面量,总结下来应该是又生成两个实例,那么一共应该是生成三个String实例。
如果说要执行多次的话,那么每一次都要增加一个String实例,因为有第一个语句。
我的理解不晓得正确与否,因为我只是看了一些介绍,并不懂得看JVM的汇编语句  回复  更多评论
  
# re: 继续巩固Java基础,一道综合题
2006-09-20 17:36 | murainwood
"Hello"如果是第一次出现,会生成一个新的实例,然后放入常量Pool中。
调用了new 语句,总能新生成一个对象实例。
所以 String a="Hello"和 String a=new String("Hello")是不同的。而且后者被认为是"劣质代码"
而a+="World";这个你可以用javap -c 来看JVM汇编码。
String做所谓的"连接"时,总是通过临时变量 StringBuffer 或StringBuilder来实现的。(后者是JDK5.0中的新类,是一个多线程不安全的StringBuffer)
  回复  更多评论
  
# re: 继续巩固Java基础,一道综合题
2006-09-20 19:17 | Winnie
正巧我对在网上看到的一些内容不是很了解,在此可否再请教一下:
“String a="Hello"和 String a=new String("Hello")是不同的”
据我在网上看到的一些资料可以这么解释:前者是生成一个引导变量a,然后查看“字符串池”中是否有hello这个常量,如果有,直接把该常量的内存地址赋值给a,如果没有,则在“字符串池”中创建一个hello实例,将新创建的内存自己赋值给a;而后者是生成一个引导变量a,同时创建一个字符串实例,将该字符串实例的内存地址赋值给a。
你在上文中提到“"Hello"如果是第一次出现,会生成一个新的实例,然后放入常量Pool中。”。我看到的一些资料说,字符串池可以理解为一块特殊的地方,和内存稍有区别。如果hello是第一次出现,那么给该实例开辟的内存空间可否认为是在pool中的,以后再次出现new语句时,再另外开辟内存空间?
换言之,String a=new String("Hello")第一次运行中,开辟了一个内存空间,且把该空间算到pool中去,如果pool中没有hello实例的话?  回复  更多评论
  
# re: 继续巩固Java基础,一道综合题
2006-09-20 21:08 | murainwood
我的观点是可以反过来想。
下面是我写的代码
//:~To compare the reference of string
public class StringConstPool {

/**
* @param args
*/
public static void main(String[] args) {

String the1st="hello";

String the2ed="hello";

//the result is "the two string are Same"
//so i'm sure the the1st and the2ed refer the same address
System.out.println("The two strings are "+(the1st==the2ed?"Same":"Different"));

String the3ed=new String("hello");
//the result is different from upper
//so the the3ed refers another address,thought they have
System.out.println("The two strings are "+(the1st==the3ed?"Same":"Different"));

}

}

可以看到,变量the1st 和 the2ed 所指的地址是一样的。而the3ed则是另外的地址。
我认为的常量池的观点是正确的,String the2ed="hello"这语句甚至一个对象实例都没有创造!

这是JDK API中文版的说明:
String
public String(String original)初始化一个新创建的 String 对象,表示一个与该参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的一个副本。由于 String 是不可变的,不必使用该构造方法,除非需要 original 的 显式副本。

很明白了吧?  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 
<2006年8月>
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789

如果真的给你一片天,你敢不敢要?

常用链接

留言簿(3)

随笔分类

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜