最近我面了12个人,发现这个JAVA基础题都答得不好

你好,我是 阿远 。
一般面试我都会问一两道很基础的题目,来考察候选人的“地基”是否扎实,有些是操作系统层面的,有些是 JAVA 语言方面的,还有些…
最近我都拿一道 Java 语言基础题来考察候选人:

不用反射,能否实现一个方法,调换两个 String 对象的实际值?
String yesA = "a";String yesB = "b";//能否实现这个 swap 方法// 让yesA=b,yesB=a?swap(yesA, yesB);别小看这道题,其实可以考察好几个点:
1.明确 yesA 和 yesB 是啥
2.Java 只有值传递
3.String 是不可变类
4.字符串常量池
5.intern 的理解
6.JVM内存的划分与改变
基于上面这几个点,其实还能发散出很多面试题,不过今天咱们这篇文章就不发散了,好好消化上面这几个点就可以了 。
我们需要明确答案:实现不了这个方法 。
按照题意,我相信你很容易能写出以下的 swap 方法实现:
void swap(String yesA, String yesB){String temp = yesA;yesA = yesB;yesB = temp;}首先,我们要知道 String yesA = "a"; 这行代码返回的 yesA 代表的是一个引用,这个引用指向堆里面的对象 a 。
最近我面了12个人,发现这个JAVA基础题都答得不好

文章插图
 
也就是说变量 yesA 存储的只是一个引用,通过它能找到 a 这个对象,所以表现出来好像 yesA 就是 a,实际你可以理解 yesA 存储是一个“地址”,Java 通过这个地址就找到对象 a 。
因此,我们知道了,yesA 存储的值不是 a,是引用(同理,yesB也一样) 。
然后,我们都听过 Java 中只有值传递,也就是调用方法的时候 Java 会把变量 yesA 的值传递到方法上定义的 yesA(同理 yesB 也是一样),只是值传递 。
根据上面我们已经知道 yesA 存储的是引用,所以我们得知,swap方法 里面的 yesA 和 yesB 拿到的是引用 。
最近我面了12个人,发现这个JAVA基础题都答得不好

文章插图
 
然后调用了 swap 方法,调换了 yesA 和 yesB 的值(也就是它的引用)
最近我面了12个人,发现这个JAVA基础题都答得不好

文章插图
 
请问,swap 里的跟我外面的 yesA 和 yesB 有关系吗?显然,没有关系 。
因此最终外面的 yesA 指向的还是 a,yesB 指向的还是 b 。
不信的话,我们看下代码执行的结果:
最近我面了12个人,发现这个JAVA基础题都答得不好

文章插图
 
现在,我们明确了,Java 只有值传递 。
看到这,可能会有同学疑惑,那 int 呢,int 不是对象呀,没引用啊,其实一样的,记住Java 只有值传递 。
我们跑一下就知道了:
最近我面了12个人,发现这个JAVA基础题都答得不好

文章插图
 
很显然,int 也无法交换成功,道理是一样的 。
外面的 yesA 和 yesB,存储的值是 1 和 2(这里不是引用了,堆里也没有对象,栈上直接分配值) 。
调用 swap 时候,传递的值是 1 和 2,你可以理解为拷贝了一个副本过去 。
所以 swap 里的 yesA 和 yesB 实际上是副本,它的值也是 1 和 2,然后副本之间进行了交换,那跟正主有关系吗?
显然没有 。
像科幻电影里面有克隆人,克隆人死了,正主会死吗?
不会 。
记住,Java 只有值传递 。
再回到这个面试题,你需要知道 String 是不可变类 。
那什么是不可变类呢?
【最近我面了12个人,发现这个JAVA基础题都答得不好】我在之前的文章说过,这边我引用一下:
不可变类指的是无法修改对象的值,比如 String 就是典型的不可变类,当你创建一个 String 对象之后,这个对象就无法被修改 。
因为无法被修改,所以像执行s += “a”; 这样的方法,其实返回的是一个新建的 String 对象,老的 s 指向的对象不会发生变化,只是 s 的引用指向了新的对象而已 。
看下面这幅图应该就很清晰了:
最近我面了12个人,发现这个JAVA基础题都答得不好

文章插图
 
如图所示,每次其实都是新建了一个对象返回其引用,并不会修改以前的对象值,所以我们常说不要在字符串拼接频繁的场景不要使用 + 来拼接,因为这样会频繁的创建对象,影响性能 。
而一般你说出 String 是不可变类的时候,面试官一般都会追问:
不可变类有什么好处?
来,我也为你准备好答案了:


推荐阅读