以下是互联网大厂 Java 求职者面试三轮问答及答案:
第一轮:
面试官:请你谈谈 Java 的基本数据类型有哪些? 王铁牛:有 byte、short、int、long、float、double、char、boolean 这几种。 面试官:不错,那你说说这些数据类型的存储大小范围分别是多少? 王铁牛:(略作思考)byte 是 8 位,存储范围是 -128 到 127;short 是 16 位,范围是 -32768 到 32767 等。 面试官:很好,那你再说说自动装箱和拆箱是怎么回事? 王铁牛:自动装箱就是把基本数据类型自动转换成对应的包装类对象,拆箱则是相反,把包装类对象转换成基本数据类型。
第二轮:
面试官:讲讲 Java 中的多线程有哪些实现方式? 王铁牛:有继承 Thread 类和实现 Runnable 接口这两种方式。 面试官:那你说说这两种方式的区别是什么? 王铁牛:(稍微犹豫)继承 Thread 类方式比较简单,但不利于代码的扩展性和复用性;实现 Runnable 接口方式更灵活,适合多个线程共享一个目标对象。 面试官:不错,那你再说说线程的生命周期有哪些状态? 王铁牛:有新建、就绪、运行、阻塞和死亡这几种状态。
第三轮:
面试官:谈谈你对 HashMap 的理解? 王铁牛:HashMap 是基于哈希表的 Map 接口的实现,它存储键值对,通过哈希函数来计算键的索引位置。 面试官:那 HashMap 的哈希冲突是怎么解决的? 王铁牛:(挠挠头)嗯……这个好像不太清楚。 面试官:(无奈)那你再说说 ArrayList 的特点吧? 王铁牛:ArrayList 是动态数组,可以根据需要自动扩容,随机访问效率高,但插入和删除元素效率较低。
面试官:今天的面试就到这里,你回家等通知吧。
答案:
关于 Java 基本数据类型:
- byte:8 位,存储范围是 -128 到 127,主要用于节省空间的整数场景,如字节流处理等。
- short:16 位,范围是 -32768 到 32767,适用于需要表示较小整数范围的情况,比如某些协议中的字段。
- int:32 位,是最常用的整数类型,范围是 -2147483648 到 2147483647,一般用于常规的整数运算。
- long:64 位,范围非常大,用于表示很大的整数,如统计数据等。
- float:32 位单精度浮点数,用于表示小数,但精度有限,适用于科学计算等对精度要求不高的场景。
- double:64 位双精度浮点数,精度比 float 高,常用于需要高精度小数的计算,如金融领域。
- char:16 位 Unicode 字符,用于表示单个字符,如处理文本字符串。
- boolean:只有 true 和 false 两个值,用于逻辑判断。
关于 Java 多线程实现方式的区别:
- 继承 Thread 类:代码实现相对简单,直接重写 run() 方法即可定义线程的执行逻辑。但这种方式不利于代码的扩展性和复用性,因为 Java 不支持多继承,一个类只能继承一个父类,所以如果已经继承了其他类,就无法再继承 Thread 类来实现多线程。
- 实现 Runnable 接口:通过实现 Runnable 接口,将线程的执行逻辑封装在 run() 方法中,然后将 Runnable 对象传递给 Thread 构造函数来创建线程。这种方式更加灵活,适合多个线程共享一个目标对象的情况,并且可以避免单继承的限制。
关于线程的生命周期状态:
- 新建(New):线程对象刚被创建,但还未启动。
- 就绪(Runnable):线程对象已经创建并且初始化完成,处于等待 CPU 分配时间片的状态,随时可以被调度执行。
- 运行(Running):线程获得 CPU 时间片,开始执行 run() 方法中的代码。
- 阻塞(Blocked):线程因为等待某个条件(如锁、IO 操作等)而暂停执行,进入阻塞状态,直到条件满足时被唤醒。
- 死亡(Dead):线程执行完毕或者因异常等原因终止,进入死亡状态,不再执行。
关于 HashMap 的哈希冲突解决方式: HashMap 使用哈希函数将键映射到哈希表中的索引位置。当多个键映射到相同的索引位置时,就会发生哈希冲突。HashMap 通常使用链表法来解决哈希冲突,即在相同索引位置的链表中存储冲突的键值对。当需要获取或存储键值对时,首先通过哈希函数计算索引位置,然后在相应的链表中进行查找或插入操作。如果链表长度超过一定阈值(默认是 8),HashMap 会将链表转换为红黑树,以提高查询效率。
关于 ArrayList 的特点:
- 动态数组:可以根据需要自动扩容,初始容量为 10,当数组满了之后会自动扩容为原来的 1.5 倍。
- 随机访问效率高:通过索引可以快速访问数组中的元素,时间复杂度为 O(1)。
- 插入和删除元素效率较低:在数组中间插入或删除元素时,需要移动后续的元素,时间复杂度为 O(n),其中 n 是数组的长度。因此,在需要频繁进行插入和删除操作的场景中,不适合使用 ArrayList,可以考虑使用 LinkedList 等数据结构。