《互联网大厂面试:Java核心知识、框架与中间件大考验》

31 阅读10分钟

互联网大厂面试:Java核心知识、框架与中间件大考验

互联网大厂的面试室内,气氛紧张而严肃。面试官正襟危坐,面前放着求职者的简历,而求职者王铁牛则略显紧张地坐在对面。

第一轮提问 面试官:“首先,我们来聊聊Java核心知识。Java中基本数据类型有哪些?” 王铁牛:“Java的基本数据类型有 byte、short、int、long、float、double、char、boolean。” 面试官:“回答得不错。那自动装箱和拆箱是怎么回事?” 王铁牛:“自动装箱就是把基本数据类型转换为对应的包装类,拆箱则相反,把包装类转换为基本数据类型。比如 Integer i = 10 就是自动装箱,int j = i 就是拆箱。” 面试官:“很好。那说说 String、StringBuilder 和 StringBuffer 的区别。” 王铁牛:“String 是不可变的,每次对 String 进行操作都会生成一个新的 String 对象。StringBuilder 是非线程安全的,而 StringBuffer 是线程安全的,它们都是可变的。一般单线程用 StringBuilder,多线程用 StringBuffer。” 面试官:“非常棒,看来你对 Java 核心基础掌握得很扎实。”

第二轮提问 面试官:“接下来谈谈多线程和 JUC。什么是线程安全?” 王铁牛:“线程安全就是在多线程环境下,程序的执行结果和单线程环境下是一样的,不会出现数据不一致等问题。” 面试官:“那说说 Java 中实现线程安全的方式有哪些?” 王铁牛:“可以用 synchronized 关键字,它可以修饰方法或者代码块,保证同一时刻只有一个线程能访问。还有使用 JUC 包下的锁,比如 ReentrantLock。” 面试官:“不错。那线程池的作用是什么,有哪些创建方式?” 王铁牛:“线程池的作用是减少线程创建和销毁的开销,提高性能。创建方式有通过 Executors 工具类创建,比如 newFixedThreadPool、newCachedThreadPool 等,也可以直接使用 ThreadPoolExecutor 类创建。” 面试官:“回答得很全面,对多线程和 JUC 有一定的理解。”

第三轮提问 面试官:“现在说说框架相关的。Spring 的核心特性有哪些?” 王铁牛:“Spring 的核心特性有 IOC(控制反转)和 AOP(面向切面编程)。IOC 是把对象的创建和依赖关系的管理交给 Spring 容器,AOP 是在不修改原有代码的基础上增强功能。” 面试官:“那 Spring Boot 有什么优势,和 Spring 有什么关系?” 王铁牛:“Spring Boot 简化了 Spring 应用的开发,它提供了自动配置,能快速搭建项目。Spring Boot 是基于 Spring 的,它让 Spring 的使用更加方便。” 面试官:“MyBatis 中 #{} 和 {} 的区别是什么?” **王铁牛**:“#{} 是预编译处理,能防止 SQL 注入,它会把参数替换为占位符。{} 是字符串替换,直接把参数拼接到 SQL 语句中,有 SQL 注入风险。” 面试官:“回答得还行。那 Dubbo 是什么,有什么作用?” 王铁牛:“Dubbo 是一个分布式服务框架,能实现服务的远程调用、服务治理等功能。” 面试官:“看来你对框架有一定的了解。”

总结 面试官推了推眼镜,看着王铁牛说:“通过这几轮的提问,能看出你对 Java 核心知识、多线程、线程池以及一些框架有一定的掌握。在简单的问题上,你回答得比较清晰准确,说明基础还是比较扎实的。但对于一些更深入的问题,你的回答还不够完善和深入,比如某些技术的原理和实际应用场景方面。我们公司需要的是对技术有深入理解,能解决实际复杂问题的人才。你先回家等通知吧,后续如果有进一步的消息,我们会及时联系你。”

问题答案详细解析

  1. Java 基本数据类型
    • Java 有 8 种基本数据类型,分为 4 类。整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节);浮点类型:float(4 字节)、double(8 字节);字符类型:char(2 字节);布尔类型:boolean(1 位)。基本数据类型是 Java 中最基础的数据表示形式,用于存储简单的数据值。
  2. 自动装箱和拆箱
    • 自动装箱是 Java 编译器在基本数据类型和对应的包装类之间进行的自动转换。例如,当把一个基本数据类型赋值给对应的包装类对象时,编译器会自动调用包装类的 valueOf 方法进行装箱。如 Integer i = 10,实际是 Integer i = Integer.valueOf(10)。拆箱则是把包装类对象转换为基本数据类型,编译器会自动调用包装类的 xxxValue 方法。如 int j = i,实际是 int j = i.intValue()。
  3. String、StringBuilder 和 StringBuffer 的区别
    • String 类是不可变的,它的底层是一个被 final 修饰的字符数组。每次对 String 进行操作,如拼接、替换等,都会创建一个新的 String 对象,原对象不会改变。这会导致大量的内存开销,尤其是在频繁操作字符串时。
    • StringBuilder 和 StringBuffer 都是可变的,它们的底层是一个动态的字符数组。StringBuilder 是非线程安全的,在单线程环境下操作效率高,因为它不需要考虑线程同步的问题。StringBuffer 是线程安全的,它的方法都使用了 synchronized 关键字进行同步,保证在多线程环境下数据的一致性,但由于同步机制会带来一定的性能开销,所以在单线程环境下效率不如 StringBuilder。
  4. 线程安全
    • 在多线程环境下,多个线程可能会同时访问和修改共享资源。如果程序没有采取适当的同步措施,就可能会出现数据不一致、脏读、幻读等问题。线程安全的程序能够保证在多线程环境下,对共享资源的访问和操作是正确的,不会出现上述问题。例如,一个计数器变量,如果多个线程同时对其进行自增操作,没有同步机制就可能导致计数结果不准确,而线程安全的计数器会通过同步机制保证每次只有一个线程能进行自增操作。
  5. Java 中实现线程安全的方式
    • synchronized 关键字:可以修饰实例方法、静态方法和代码块。修饰实例方法时,锁的是当前对象实例;修饰静态方法时,锁的是当前类的 Class 对象;修饰代码块时,需要指定一个锁对象。synchronized 关键字通过互斥锁的机制,保证同一时刻只有一个线程能进入被修饰的方法或代码块,从而实现线程安全。
    • JUC 包下的锁:如 ReentrantLock。ReentrantLock 是一个可重入锁,它提供了比 synchronized 更灵活的锁机制,例如可以实现公平锁和非公平锁,可以进行锁的中断和超时等待等操作。使用时需要手动加锁和解锁,一般通过 try-finally 块来确保锁一定会被释放。
  6. 线程池的作用和创建方式
    • 作用:在多线程编程中,频繁地创建和销毁线程会带来很大的开销,影响系统的性能。线程池可以预先创建一定数量的线程,当有任务提交时,从线程池中获取线程来执行任务,任务执行完后线程不会销毁,而是返回线程池等待下一个任务。这样可以减少线程创建和销毁的开销,提高系统的响应速度和性能。
    • 创建方式
      • Executors 工具类:提供了一些静态方法来创建不同类型的线程池。例如,newFixedThreadPool 创建一个固定大小的线程池,线程数量固定,当有新任务提交时,如果线程池中有空闲线程就执行,否则任务会在队列中等待;newCachedThreadPool 创建一个可缓存的线程池,线程数量可以动态变化,当有新任务提交时,如果线程池中有空闲线程就执行,否则会创建新的线程,当线程空闲一段时间后会被销毁。
      • ThreadPoolExecutor 类:可以通过构造函数来创建自定义的线程池,需要指定核心线程数、最大线程数、线程空闲时间、任务队列等参数,这种方式更加灵活,可以根据实际需求进行定制。
  7. Spring 的核心特性
    • IOC(控制反转):传统的程序中,对象的创建和依赖关系的管理是由程序本身负责的,而在 Spring 中,把这些工作交给了 Spring 容器。Spring 容器通过配置文件或注解来创建和管理对象,对象之间的依赖关系也由容器来注入。这样可以降低代码的耦合度,提高代码的可维护性和可测试性。例如,一个 Service 类依赖一个 DAO 类,在传统方式中,Service 类需要自己创建 DAO 类的实例,而在 Spring 中,Service 类只需要声明对 DAO 类的依赖,Spring 容器会自动创建和注入 DAO 类的实例。
    • AOP(面向切面编程):AOP 是一种编程范式,它可以在不修改原有代码的基础上,对程序的某些功能进行增强。在 Spring 中,AOP 主要用于实现日志记录、事务管理、权限验证等功能。AOP 通过定义切面(Aspect)、切入点(Pointcut)和通知(Advice)来实现。切面是一个包含了多个通知和切入点的模块,切入点定义了哪些方法需要被增强,通知定义了在切入点的什么位置执行增强代码,如前置通知、后置通知、环绕通知等。
  8. Spring Boot 的优势和与 Spring 的关系
    • 优势:Spring Boot 简化了 Spring 应用的开发过程,它提供了自动配置功能,根据项目中引入的依赖自动进行配置,减少了大量的配置文件和样板代码。同时,Spring Boot 提供了嵌入式的服务器,如 Tomcat、Jetty 等,可以直接将应用打包成可执行的 JAR 文件,方便部署和运行。此外,Spring Boot 还提供了 Actuator 等工具,方便对应用进行监控和管理。
    • 关系:Spring Boot 是基于 Spring 框架构建的,它继承了 Spring 的核心特性,如 IOC 和 AOP。Spring Boot 是对 Spring 的进一步封装和优化,让开发者可以更快速、更方便地使用 Spring 框架来开发应用。
  9. MyBatis 中 #{} 和 ${} 的区别
    • #{}:是预编译处理,在 SQL 语句中使用 #{} 时,MyBatis 会把 #{} 替换为占位符(?),然后使用 PreparedStatement 来执行 SQL 语句。这样可以防止 SQL 注入攻击,因为参数会被作为一个整体进行处理,不会和 SQL 语句进行拼接。例如,在查询语句中使用 #{} 来接收用户输入的参数,MyBatis 会自动对参数进行转义,避免恶意的 SQL 注入。
    • **:是字符串替换,MyBatis会直接把{}**:是字符串替换,MyBatis 会直接把 {} 替换为参数的值,然后拼接成完整的 SQL 语句。这种方式存在 SQL 注入风险,因为如果参数包含恶意的 SQL 语句,会直接拼接到原 SQL 中执行。例如,如果用户输入的参数包含分号和其他恶意 SQL 语句,使用 {} 会导致原 SQL 语句被篡改,从而引发安全问题。所以在实际开发中,尽量使用 #{} 来传递参数,只有在需要动态表名、列名等情况下才使用 {}。
  10. Dubbo 是什么及作用
    • Dubbo 是阿里巴巴开源的一个高性能、轻量级的分布式服务框架,用于实现服务的远程调用和服务治理。在分布式系统中,不同的服务可能部署在不同的服务器上,Dubbo 可以实现服务之间的远程调用,就像调用本地方法一样方便。它提供了多种远程调用协议,如 Dubbo 协议、HTTP 协议等。
    • Dubbo 的服务治理功能包括服务注册与发现、负载均衡、集群容错等。服务提供者可以将自己的服务注册到注册中心,服务消费者可以从注册中心获取服务提供者的地址信息,然后进行远程调用。负载均衡功能可以根据一定的算法(如随机、轮询等)选择合适的服务提供者进行调用,提高系统的性能和可用性。集群容错功能可以在服务提供者出现故障时,自动进行重试或切换到其他服务提供者,保证服务的正常运行。