您的位置:首页 > 职场人生

由面试题引发对java字符串思考【转】

2011-10-23 15:10 435 查看
身边有些做Java开发的朋友,找工作时常常被考到一道关于字符串的题目。题目倒是很基础,然而根据朋友们事后的描述,有理由认为有的面试官自己都没有完全搞清楚这个问题。此外,在CSDN论坛中我也多次看到一些朋友在这个问题上的迷惑。索性把自己的理解写下来吧。

题目是一道简单的小程序,像下面这样:

view plaincopy
to clipboardprint?

public class Test1 {
public static void main(String args[]) {
String s = new String("Hello");
System.out.println(s);

foo(s);
System.out.println(s);
}

public static void foo(String s) {
s = new String("World");
}
}

view plaincopy
to clipboardprint?

public class Test2 {
public static void main(String args[]) {
StringBuilder s = new StringBuilder("Hello");
System.out.println(s);

foo(s);
System.out.println(s);
}

public static void foo(StringBuilder s) {
s = new StringBuilder("World");
}
}

public class Test2 { public static void main(String args[]) {  StringBuilder s = new StringBuilder("Hello");  System.out.println(s);  foo(s);  System.out.println(s); } public static void foo(StringBuilder s) {  s = new StringBuilder("World"); }}

这次呢?会先输出“Hello”,然后输出“World”吗?不会,仍然是两次“Hello”。

足以说明这个问题跟String的immutable特性没有一毛钱的关系。不管是immutable类型,还是一般的类型,用这种方式写出来的程序main方法中前后两个对象肯定是一样的。

真正的原因是:Java语言的参数传递机制是“按值传递”(pass by value)。虽然Java中除基本数值类型外,其它变量都是引用,但那是另一回事。变量的语义(“引用”还是“值”)跟函数传参的机制是两个正交的概念。

各种编程语言中,最常见的参数传递方式不外乎按值传递和按引用传递(pass by reference)两种。比如,C和Java中函数参数都是按值传递的,C++和C#则同时支持按值传递和按引用传递。C和Java的不同在于,C是值类型的按值传递,而Java是引用类型的按值传递(基本的数值类型除外)。

按值传参最大的特点就是函数内部对“形参变量”本身的所做的修改外面的“实参变量”感知不到。

不过,对于StringBuilder来说我们至少有办法让它改变,比如像下面这样:

view plaincopy
to clipboardprint?

public class Test3 {
public static void main(String args[]) {
StringBuilder s = new StringBuilder("Hello");
System.out.println(s);

foo(s);
System.out.println(s);
}

public static void foo(StringBuilder s) {
s.replace(0, s.length(), "World");
}
}

public class Test3 { public static void main(String args[]) { StringBuilder s = new StringBuilder("Hello"); System.out.println(s); foo(s); System.out.println(s); } public static void foo(StringBuilder s) { s.replace(0, s.length(), "World"); }}
体会到不同了吗?虽然参数变量本身是按值传递的,但这次我们对变量本身不感兴趣,我们不改变变量本身,而是通过它直接修改它所引用的那个对象。这一次,Java语言“几乎一切皆引用”的特点起作用了,程序第一次输出“Hello”,第二次输出“World”。熟悉C的朋友可能马上联想到:这很像C语言中通过指针来修改它指向的内容。

而先前那个String版本的程序,我们无法写出一个相应的可变版本。为什么呢?……“嗯,不错不错。因为String是immutable类型……”,这次真对了。——可见先前说“没有一毛钱的关系”也不尽然。因为immutable,导致我们无法针对String写出一个像Test3那样的“可变”程序,如此说来,“二分钱的关系”应该是有的。

“pass reference by value”就像C++ 11中的“An lvalue with rvalue reference type”一样,乍一看挺绕的,但只要仔细想清楚,让正交的东西“尘归尘 土归土”,就可以加深对语言的理解。

顺便问一句,您知道java.lang.StringBuilder和java.lang.StringBuffer的区别吗?好多面试官都喜欢“顺便”问问这个,而且答对了不会加分,答不上来却会扣分,至少扣印象分。:(
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: