《互联网大厂 Java 求职者面试三轮问答及答案》

54 阅读4分钟

以下是《互联网大厂 Java 求职者面试三轮问答及答案》:

第一轮: 面试官:请你谈谈 Java 的基本数据类型有哪些? 王铁牛:有 byte、short、int、long、float、double、char、boolean 这几种。 面试官:不错,那说说它们各自的取值范围吧。 王铁牛:byte 的取值范围是 -128 到 127,short 是 -32768 到 32767,int 是 -2147483648 到 2147483647,long 是更大的范围,float 是单精度浮点数,double 是双精度浮点数,char 表示字符,取值范围是 0 到 65535,boolean 只有 true 和 false 两个值。 面试官:回答得很清晰,那再说说 Java 中的运算符有哪些? 王铁牛:有算术运算符(如 +、-、*、/、%)、关系运算符(如 ==、!=、>、<、>=、<=)、逻辑运算符(如 &&、||、!)、位运算符(如 &、|、^、~、>>、<<、>>>)等。 面试官:很好,你可以先回去等通知了。

第二轮: 面试官:在 Java 中,如何实现多线程? 王铁牛:可以通过继承 Thread 类或实现 Runnable 接口来实现多线程。 面试官:那这两种方式有什么区别呢? 王铁牛:继承 Thread 类比较简单,直接重写 run 方法即可,但 Java 不支持多重继承,所以如果已经继承了其他类就不能再继承 Thread 类了;而实现 Runnable 接口则更加灵活,可以避免单继承的限制,多个线程可以共享同一个 Runnable 对象的实例。 面试官:嗯,理解得很到位。那说说线程的生命周期吧。 王铁牛:线程的生命周期包括新建、就绪、运行、阻塞和死亡五个状态。新建状态是刚创建线程对象但还未启动;就绪状态是线程对象创建后调用 start 方法,等待 CPU 调度;运行状态是线程获得 CPU 资源正在执行代码;阻塞状态是线程因为某些原因(如等待锁、IO 操作等)暂停执行;死亡状态是线程执行完毕或出现异常终止。 面试官:非常好,你先回去等消息吧。

第三轮: 面试官:在 Java 中,HashMap 的底层原理是什么? 王铁牛:HashMap 的底层是数组和链表的结合。数组用于存储键值对,链表用于解决哈希冲突。当添加元素时,根据键的哈希值计算出数组的索引位置,如果该位置已经有元素,就通过链表连接起来。 面试官:那 HashMap 的负载因子是多少?为什么要设置负载因子? 王铁牛:默认的负载因子是 0.75。设置负载因子是为了在空间和时间之间进行平衡。如果负载因子太小,会导致哈希表中的链表过长,查询效率降低;如果负载因子太大,会导致哈希冲突增加,也会影响查询效率。 面试官:很好,那 HashMap 是线程安全的吗?如果不是,如何实现线程安全的哈希表? 王铁牛:HashMap 不是线程安全的。可以使用 Collections.synchronizedMap 方法将 HashMap 包装成线程安全的 Map,或者使用 ConcurrentHashMap 来实现线程安全的哈希表。 面试官:非常棒,你可以回去等通知了,我们会尽快给你回复的。

答案:

  • Java 的基本数据类型及其取值范围:
    • byte:-128 到 127,占用 1 个字节。
    • short:-32768 到 32767,占用 2 个字节。
    • int:-2147483648 到 2147483647,占用 4 个字节。
    • long:更大的范围,占用 8 个字节。
    • float:单精度浮点数,占用 4 个字节。
    • double:双精度浮点数,占用 8 个字节。
    • char:表示字符,取值范围是 0 到 65535,占用 2 个字节。
    • boolean:只有 true 和 false 两个值,占用 1 位。
  • 实现多线程的方式及区别:
    • 继承 Thread 类:简单直接,重写 run 方法,如 class MyThread extends Thread { public void run() { // 线程执行的代码 } }。但 Java 不支持多重继承,已继承其他类时不能再继承 Thread 类。
    • 实现 Runnable 接口:更加灵活,避免单继承限制,多个线程可共享同一个 Runnable 对象实例,如 class MyRunnable implements Runnable { public void run() { // 线程执行的代码 } },然后通过 Thread thread = new Thread(new MyRunnable()); thread.start(); 启动线程。
  • HashMap 的底层原理:
    • 底层是数组和链表的结合。数组用于存储键值对,通过哈希函数计算键的哈希值,根据哈希值确定在数组中的索引位置。当多个键的哈希值相同(哈希冲突)时,通过链表连接起来。
  • HashMap 的负载因子及作用:
    • 默认负载因子是 0.75。它用于在空间和时间之间进行平衡,太小会导致哈希表中的链表过长,查询效率降低;太大则会导致哈希冲突增加,也影响查询效率。
  • HashMap 是否线程安全及实现线程安全的方式:
    • HashMap 不是线程安全的。可以使用 Collections.synchronizedMap 方法将 HashMap 包装成线程安全的 Map,如 Map synchronizedMap = Collections.synchronizedMap(new HashMap());;或者使用 ConcurrentHashMap 来实现线程安全的哈希表,它在内部使用了分段锁等机制来提高并发性能。