您的位置:首页 > 编程语言 > Java开发

thinking in java test5.1练习(1)(2)

2016-08-16 20:57 411 查看
练习(1)题目:创建一个类,它包含一个未初始化的String引用。验证该引用被Java初始化成了null。

代码如下:

public class Test5_1_1 {
public static void main(String[] args){
Test t = new Test();
System.out.println(t.str);
}
}
class Test{
String str;
}




打开源码查看一下:

/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence.  Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.value = "".value;
}


我们发现如果没有给String类初始化内容,系统会默认把“”的值赋给它,也就是null。

练习(2)题目:创建一个类,它包含一个在定义时就被初始化了的String域,以及另一个通过构造器初始化的String域。这两种方式有何差异?

代码如下:

class Test{
String str = "123";
String string =new String("234");
}


没差异吗?当然有差异了。

jvm对string,有一个专门的string pool(字符串池)来存储,我们看下面这个例子:

public static void main(String[] args){
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);//结果是true
}


粗看似乎打印的结果应该是false,因为==在比较引用时比较的是地址,但程序运行的结果是true,因为s1和s2两个引用指向的地址是同一个。

当你用String s1 = “abc”声明一个字符串时,jvm会先在字符串池里检查是否存在“abc”这个字符串,若存在,则指向它,不存在,则创建一个“abc”,再指向它。所以这里s1和s2指向的是同一个字符串。(jvm这么做是为了节省内存开销)。

而当我们String str = new String(“234”);时,首先,在堆里创建一个String对象,然后str指向这个对象。同时,jvm会检查字符串池,若字符串池中有“234”,就把这个字符串交给这个新建出来的对象持有,如果没有,则在字符串池中创建一个新字符串“234”,再把它交给对象。要注意的是,不管在创建对象时字符串池中有木有“234”,str始终指向新创建的对象,也就是str的值是对象堆空间的地址。至于字符串池中对象“234”,的地址,则存放在堆中。如图所示:



看代码:

public static void main(String[] args){
String s1 = "abc";
System.out.println(s1 == new String("abc"));//打印结果是false
}


所以两种方式,一个是放在单独管理的字符串池里,一个是放在堆里开辟的对象空间里。是有根本区别的。

PS:一个经典面试题:

String s=new String(“abc”);

String s1=”abc”;

String s2=new String(“abc”);

上段代码究竟产生了几个对象?

我们来分析程序运行过程:首先声明引用s,在堆中创建一个新的String对象,s指向这个对象,与此同时,检测字符串池中有木有“abc”,发现没有,就创建一个。

此时,已经创建了两个对象。

然后第二行代码:String s1 = “abc”;jvm检查发现字符串池中有“abc”了,于是直接将s1指向它,这句代码没有创建新对象。

第三行代码,同第一行一样,声明引用s2,创建新对象,s2指向新对象,同时检查字符串池中有没有“abc”,发现有,就将起地址给新对象。

所以答案是三个对象。

当然如果在面试中遇到这个问题,我们也可以耍一下小聪明,说两个或三个,因为我们不清楚在这三行代码的前文,是否已经在字符串池中创建了“abc”对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java