一道印象深刻的面试题:String参数传递问题

         今天小菜去北京某知名公司面试,做了公司的面试题,然后就是轻松的面试。

         面试过程中,面试官让我讲讲其中一个题是怎么选的答案,代码大致内容如下:

 

 1 public class StringTest{
 2     public static void main(String[] args){
 3         String str = "s";
 4         
 5         changeStr(str);
 6         
 7         System.out.println(str);
 8         
 9     }
10     
11     private static void changeStr(String old){
12         old = old + "-change";
13     }
14     
15 }

 

 

         真实的输出结果应该是s,而小菜则错误的认为是s-change,还跟面试官讲了一堆道理。

         事后瞬间感觉学艺不精,羞愧难当。。。。

         这个结果为什么s呢?经过查阅资料,原来是String虽然以对象的形式存在,但仍认为是基本数据类型,就像Integer、Double那样,虽然是基本类型的包装类,但仍然认为是基本数据类型。

         既然认为是基本数据类型,因此无论在方法中如何操作,都不会影响到外界。

         其实,换个角度,也可以发现这样是错误的。

         首先,大家都知道字符串是不可改变的,简单理解即可,不做深入讨论。

         当我们把字符串当成参数传入方法时,传递的是值,是一个指针,这个指针指向了堆区的真实字符串,因此在方法中可以读到这个字符串,但是仅仅是能读到而已,当我们试图做如下操作时:

         str = str.replace(“a”,”b”);

         后边的str中保存的是原来的指针,的确是可以读到原来的字符串,然后执行替换操作,但是替换操作执行时,绝对不可能去修改原来的字符串,因为字符串是不可变的,因此只能是在堆区产生一个新的字符串,然后把新字符串的地址(指针)赋给str。

         此时str中保存的已经不再是原来的指针,因此读出的内容发生了变化,但不代表原来指针指向的内容发生了变化。

         另外,小菜顺便再补充一个知识点。

         关于Integer i = 1;和Integer i = new Integer(1);的区别。

         Integer i = 1;会直接从常量池中找到1,然后把地址赋给i,这样充分利用常量池,节省内存,注意除了字符串,其他类型的常量池都是有范围的,超范围了失效。

         Integer i = new Integer(1);这样写,写多少次,就在内存中创建多少个对象,每个对象里都保存了一个数字1,因此这样是极其浪费内存的,不推荐使用。

         常量池是保存在堆中的。

 

         小菜水平有限,不当之处多多包涵!

 

 

posted @ 2013-07-18 22:13  杨元  阅读(2654)  评论(6编辑  收藏  举报