> 文档中心 > 面试题解(Day01)

面试题解(Day01)

今天在上课期间,有几个同学在问我一些面试题的问题,仔细看过题目之后,感觉题目还有点意思,考察的方面还是比较细节的,所以在给他们解释之后,自己回头还看了看,觉得可以写出一份博客来记录。

第一道题目是这样的:

1.Java工具类Arrays.asList()方法把数组转换成集合时,对该集合进行以下函数操作会出现错误的是()

A. size

B. add

C. remove

D. clear
这道题我第一眼看到的时候是有点疑惑的,我感觉他就是个集合的问题,在底层源码里面它应该是有这几种方法的,所以我给他们说的是应该这些方法都能够使用,但是当我自己阅读过源码之后,我发现我错了,我不仅错了而且错的很离谱。我忽略了对于底层源码的了解。
所以,我把我犯的错总结一下,写成博客的形式,希望我的拙见可以被大家认可。
解析过程是这样的:我写一个程序,给大家仔细说一下这个题目。
在里面使用的方法有:

Java.util下的一个工具类,它有一个方法叫做asList
asList的作用,就是将你传进来的一个数组,帮你变成一个集合,
数组是如何传的呢,它其实是利用一个动态列表的形式。
返回值是一个list集合,集合是可以泛型的,这里我们泛型的是String

import java.util.Arrays;import java.util.List;public class Test01 {    public static void main(String[] args) { List<String>  list = Arrays.asList("a","b","c","d"); System.out.println(list.size()); // list.add("Z");// list.remove("a");// list.clear();    }}

当程序执行的时候,当执行第一个输出语句,即 System.out.println(list.size());语句的时候,它会正确输出list中的长度,程序运行结果是,4。这个是没有问题的。这个方法是可以使用的。
但是,当我们使用下面的方法的时候,比如我们使用add这个方法的时候,它就会出现异常,异常结果是:UnsupportedOperationException,另外,使用下面的remove,clear方法的时候也是会出现异常,而且异常还是和add的异常一样,都是UnsupportedOperationException。至于为什么会出现这样的问题,我们就需要对底层源码进行剖析。
打开asList,方法是这样的,如果你传过来的是个数组,这个数组我就给你拿过来给你构建一个集合,看起来好像是new了一个集合,但这个集合是不是我们用到的呢,答案是非也,当你点进去看这个集合,
在这里插入图片描述,点击这个ArrayList集合,前面没有修饰符,继续往上查看,会看到这个,在这里插入图片描述
,也就是说,它是自己定义了一个内部类,私有的静态内部类,它也叫做arrayList,但它不是我们使用的在java.util下的那个,所以它其实就是一个自己的一个集合,在这个集合当中,只提供了size方法,还有诸如toArray,还有get,set方法,indexof,contains,等等方法当我们仔细阅读完源码之后,我们会发现,它当中没有给我们提供add,remove和clear等等一些我们常用的方法。所以说,它看起来是个集合,但不是我们常用的那个。
考察点:考察是否对底层原理的理解。
个人感觉:这道题目就是考察我们对于底层原理的理解能力,考察的较为细节。

第二道题目是这样的:

2.一道关于String底层的问题的+拼接以及==和equals的考察问题。
相信很多人都接触过Java,而且对于Java也能较为熟练的掌握,但是,当你问他这几个的区别和联系的时候,他也有可能答不上来,这里我就举一个简单的例子来解释一下,仅代表个人拙见。

曾经有一个不是我同专业的女孩子问过我这个问题,但是当初的我没好好给她解释这个问题,现在想想,真的是,哎。好了,不说闲言了,上题目:

public class Test02 {    public static void main(String[] args) { String A = "aaa"; String B = "aaa"; String C = A+B; String D = "aaa"+"aaa"; System.out.println(C==D);//false System.out.println(C.equals(D));//true    }}

这道题其实并不难,我们先来说说这道题的结果是什么?第一个C==D的结果应该是false,第二个.equals(D)的结果是true。到这里就会有同学好奇了,说为什么是这样的呢,如果有一点基础的同学应该知道,这里的这个aaa是一个常量,也就是我们常说的常量对象,它储存的位置是我们的字符串常量区当中,常量对象在编译加载的时候只有一份。在这里的意思就是,这里的A和B这两个String型的变量的空间指向的是同一个常量对象aaa,C在这里呢它是等于A+B的,大家知道,这里的+底层所做的事情是什么呢,它其实做的是一个关于StringBuilder的拼接,(这里不懂String的同学可以稍候一下,过些天我把StringBuffer,StringBuilder的联系和区别总结一下发出来),其实就是产生了一个StringBuilder的对象,它把A先放进,然后再把B通过append再放入,它是变完之后再变成toString再变回来,所以它底层就是做了一个StringBuilder的拼接过程,现在这里的两个aaa想加之后,它在底层就不是使用的StringBuilder的拼接,这里的aaa就是直接拼接起来,在编译的时候,你会发现。它的底层是不同的,打开class字节码文件,在这里插入图片描述
你会发现,这里的String D = “aaaaaa”;是和我们源码是不一样的,这里的D是直接把两个aaa拼接在了一起,按照我的理解是,就是它直接将我们这个D变成了一个字符串常量对象,所以这里这个常量字符串对象,我们当然是储存在我们的字符串常量区当中。而C呢就是产生了一个新的StringBuilder的对象,再通过toString再变回来,所以C和D就肯定不是一个对象。所以这样的情况下,你去使用 ==号去比较的时候,两个对象的内存地址是不相同的,所以它的结果就是false。但是,如果是.equals()呢,它比较的是一个值,就是将一个值循环的方式一个一个进行比较的,所以它最后的结果就是true。
再补充一点,在String类里面提供了一个方法,叫做concat()方法,该方法用于讲两个字符串拼接为同一个字符串,与+连接符类似。

String A = "aaa"; String B = "aaa"; String C = A.concat(B); System.out.println(C);

个人感觉:考察的不仅有String类的问题,还有jvm的字符常量池的问题