在互联网大厂的面试现场,面试官严肃地坐在桌前,等待着求职者的到来。不久,程序员王铁牛走进了面试房间,眼神中透露出一丝紧张。
面试官:(微笑着)你好,王铁牛,请坐。我们开始面试吧,首先我想了解一下你对 Java 核心知识的掌握程度。
第一轮: 面试官:Java 中的基本数据类型有哪些? 王铁牛:有 byte、short、int、long、float、double、char、boolean 这八种。 面试官:很好,那你说说这些数据类型的默认值分别是多少? 王铁牛:byte 的默认值是 0,short 的默认值是 0,int 的默认值是 0,long 的默认值是 0L,float 的默认值是 0.0f,double 的默认值是 0.0d,char 的默认值是 '\u0000',boolean 的默认值是 false。 面试官:不错,看来你对基本数据类型很熟悉。那再问你一个问题,Java 中的访问修饰符有哪些? 王铁牛:有 private、protected、public 和 default(缺省)这四种。
第二轮: 面试官:在多线程编程中,synchronized 关键字的作用是什么? 王铁牛:它可以用于修饰方法或代码块,保证在同一时刻只有一个线程可以访问被修饰的代码。 面试官:非常好,那你能说说 synchronized 关键字在修饰方法和代码块时有什么区别吗? 王铁牛:当修饰方法时,锁住的是当前对象;当修饰代码块时,锁住的是指定的对象。 面试官:嗯,理解得很到位。那再问你一个关于多线程的问题,线程池的作用是什么? 王铁牛:线程池可以提高线程的复用性,减少创建和销毁线程的开销,同时还可以控制线程的数量,避免线程过多导致系统资源耗尽。
第三轮: 面试官:在 JVM 中,垃圾回收的算法有哪些? 王铁牛:有标记-清除算法、复制算法、标记-整理算法。 面试官:能简单说说这些算法的特点吗? 王铁牛:标记-清除算法简单但会产生内存碎片;复制算法效率高但浪费空间;标记-整理算法解决了内存碎片问题且比较高效。 面试官:很好,最后问你一个关于 Spring 的问题,Spring 的依赖注入是怎么实现的? 王铁牛:(挠挠头)这个……不太清楚。
面试官:(摇摇头)没关系,今天的面试就到这里吧,你可以回去等通知。希望你能在以后的学习中不断提升自己的技术水平。
答案:
- Java 中的基本数据类型及其默认值:
- byte:默认值为 0,用于表示 8 位有符号整数,范围是 -128 到 127。
- short:默认值为 0,用于表示 16 位有符号整数,范围是 -32768 到 32767。
- int:默认值为 0,用于表示 32 位有符号整数,范围是 -2147483648 到 2147483647。
- long:默认值为 0L,用于表示 64 位有符号整数,范围是 -9223372036854775808 到 9223372036854775807。
- float:默认值为 0.0f,用于表示单精度浮点数。
- double:默认值为 0.0d,用于表示双精度浮点数。
- char:默认值为 '\u0000',用于表示单个字符。
- boolean:默认值为 false,用于表示布尔值。
- synchronized 关键字在修饰方法和代码块时的区别:
- 修饰方法时,锁住的是当前对象。也就是说,同一时刻只有一个线程可以进入该对象的同步方法。
- 修饰代码块时,锁住的是指定的对象。可以通过指定不同的对象来实现不同代码块的同步。
- 线程池的作用:
- 提高线程的复用性:线程池中的线程可以重复使用,避免了每次创建和销毁线程的开销。
- 减少系统资源消耗:创建和销毁线程需要消耗系统资源,而线程池可以控制线程的数量,避免线程过多导致系统资源耗尽。
- 便于线程管理:可以通过线程池来管理线程的创建、销毁、调度等操作,提高了线程管理的效率。
- JVM 中垃圾回收的算法:
- 标记-清除算法:简单直接,首先标记出所有需要回收的对象,然后统一回收这些对象所占用的内存空间。但该算法会产生内存碎片,导致后续内存分配效率降低。
- 复制算法:将内存空间分为大小相等的两块,每次只使用其中一块,当这一块的内存用完后,将还存活的对象复制到另一块上,然后清除这一块的内存。该算法效率高,但浪费了一半的内存空间。
- 标记-整理算法:标记出所有需要回收的对象,然后将存活的对象向一端移动,最后清除边界以外的内存。该算法解决了内存碎片问题,且比较高效。
- Spring 的依赖注入实现方式:
- Spring 通过容器来管理对象的创建和依赖关系。在 Spring 中,使用注解(如 @Autowired)或 XML 配置来声明依赖关系。当容器创建对象时,会根据声明的依赖关系自动注入所需的对象。例如,使用 @Autowired 注解可以在类的属性上标注,容器会自动查找并注入对应的对象。这样可以实现对象之间的解耦,提高了代码的可维护性和可扩展性。