关于JAVA的一道面试题

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

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

view plain

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");

}

}

问程序先后两次分别会输出什么。

第一个肯定输出“hello”。关键是第二个,个别基础不牢的朋友可能被考倒,但基础稍微扎实一点的就不会。第二个输出的也是“hello”。

到这里,万事大吉。面试官两眼放出喜悦的光芒,赞叹道:“嗯,不错不错。不会变的,对吧。因为string是immutable类型,immutable类型改不了的。”他说的“immutable”是指string类没有任何一个方法会改变对象的状态。

这可就有问题了。确实程序两次输出的都是“hello”,但原因却不是string的immutable特性。不信换一个“mutable”的试试,比如stringbuilder或stringbuffer。

view plain

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 plain

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的区别吗?好多面试官都喜欢“顺便”问问这个,而且答对了不会加分,答不上来却会扣分,至少扣印象分。:(


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值