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

47 阅读2分钟

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

王铁牛怀揣着紧张又期待的心情,走进了互联网大厂的面试间。一位神情严肃的面试官正坐在桌前,面前放着他的简历。面试正式开始。

第一轮提问 面试官:首先问你几个 Java 核心知识的问题。Java 中基本数据类型有哪些? 王铁牛:这个我知道,有 byte、short、int、long、float、double、char、boolean。 面试官:回答得不错。那你说说面向对象的四大特性是什么? 王铁牛:是封装、继承、多态和抽象。 面试官:很好。那在 Java 中,String 类为什么是不可变的? 王铁牛:因为 String 类被 final 修饰,它的成员变量也是 final 的,所以一旦创建就不可变了。 面试官:回答得很清晰,基础很扎实。

第二轮提问 面试官:接下来我想问一些关于并发编程的问题。JUC 包是什么,有什么作用? 王铁牛:JUC 就是 java.util.concurrent 包,里面提供了很多并发编程的工具类,能方便我们进行多线程编程。 面试官:那线程池的好处有哪些? 王铁牛:可以降低资源消耗,提高响应速度,还能方便管理线程。 面试官:当线程池的任务队列满了,并且线程数达到最大线程数时,会发生什么? 王铁牛:呃……这个……好像会拒绝任务吧,但具体怎么拒绝我有点不太清楚。 面试官:基本方向是对的,不过你可以再深入学习下拒绝策略的具体内容。

第三轮提问 面试官:现在来聊聊框架相关的问题。Spring 框架的核心是什么? 王铁牛:Spring 核心是 IOC(控制反转)和 AOP(面向切面编程)。 面试官:那 Spring Boot 相比 Spring 有什么优势? 王铁牛:Spring Boot 可以快速搭建项目,自动配置,减少了很多配置文件。 面试官:在 MyBatis 中,#{} 和 ${} 的区别是什么? 王铁牛:这个……我记得一个是预编译,一个不是,但具体哪个是哪个我有点乱了。 面试官:你有一定的印象,但还不够清晰,需要再巩固下。

面试接近尾声,面试官扶了扶眼镜,对王铁牛说道:“今天的面试就到这里了,你整体有一定的 Java 基础,对于一些简单的概念回答得不错,但在一些复杂的技术细节上还存在不足,需要进一步学习和理解。你先回家等通知吧,我们后续会综合评估后给你反馈。”

问题答案详细解析

  1. Java 中基本数据类型有哪些?
    • Java 有 8 种基本数据类型,分为 4 类:
      • 整数类型:byte(1 字节,-128 到 127)、short(2 字节,-32768 到 32767)、int(4 字节,-2147483648 到 2147483647)、long(8 字节,-9223372036854775808 到 9223372036854775807)。
      • 浮点类型:float(4 字节,单精度浮点数)、double(8 字节,双精度浮点数)。
      • 字符类型:char(2 字节,用于表示单个字符,采用 Unicode 编码)。
      • 布尔类型:boolean(只有两个值,true 和 false)。
  2. 面向对象的四大特性是什么?
    • 封装:将数据和操作数据的方法绑定在一起,隐藏对象的内部实现细节,只对外提供必要的接口。这样可以提高代码的安全性和可维护性。例如,一个类的成员变量可以设置为 private,通过 public 的 getter 和 setter 方法来访问和修改。
    • 继承:允许一个类继承另一个类的属性和方法,被继承的类称为父类(基类),继承的类称为子类(派生类)。继承可以实现代码的复用和扩展。例如,子类可以继承父类的方法,并可以重写父类的方法以实现不同的功能。
    • 多态:同一个方法可以根据对象的不同类型表现出不同的行为。多态的实现方式有方法重载和方法重写。方法重载是指在一个类中定义多个同名但参数列表不同的方法;方法重写是指子类重写父类的方法。例如,一个父类的引用可以指向不同的子类对象,调用同一个方法时会根据实际对象的类型执行不同的方法实现。
    • 抽象:抽象是指将一类对象的共同特征总结出来,形成抽象类或接口。抽象类不能实例化,它可以包含抽象方法和具体方法;接口中只能定义抽象方法和常量。抽象可以提高代码的可扩展性和可维护性。例如,定义一个抽象的 Shape 类,包含一个抽象的 draw 方法,不同的子类(如 Circle、Rectangle)可以实现这个 draw 方法来绘制不同的图形。
  3. 在 Java 中,String 类为什么是不可变的?
    • String 类被 final 修饰,意味着它不能被继承。其内部的字符数组 value 也是 final 的,一旦初始化后,数组的引用不能再改变。虽然数组本身是可变的,但 String 类没有提供修改字符数组内容的公共方法,所以 String 对象一旦创建,其内容就不能被改变。
    • 不可变的好处有:
      • 安全性:在多线程环境中,不可变对象是线程安全的,因为多个线程可以同时访问同一个 String 对象而不会出现数据不一致的问题。
      • 缓存:String 类的不可变性使得它可以被缓存,例如字符串常量池,相同内容的字符串可以共享同一个对象,节省内存。
      • 哈希码缓存:由于 String 对象不可变,它的哈希码可以被缓存,在作为哈希表的键时可以提高性能。
  4. JUC 包是什么,有什么作用?
    • JUC 即 java.util.concurrent 包,是 Java 提供的用于并发编程的工具包。它在 Java 5 中引入,为开发者提供了更高级、更方便的并发编程解决方案。
    • 作用:
      • 提供了线程安全的集合类,如 ConcurrentHashMap、CopyOnWriteArrayList 等,这些集合类在多线程环境下可以安全地进行读写操作。
      • 提供了线程池框架,方便管理线程的创建、执行和销毁,提高线程的使用效率。
      • 提供了锁机制,如 ReentrantLock、ReadWriteLock 等,用于实现更灵活的线程同步。
      • 提供了并发工具类,如 CountDownLatch、CyclicBarrier、Semaphore 等,用于协调多个线程之间的执行顺序和资源共享。
  5. 线程池的好处有哪些?
    • 降低资源消耗:线程的创建和销毁需要消耗系统资源,使用线程池可以避免频繁地创建和销毁线程,通过复用线程来降低资源消耗。
    • 提高响应速度:当有任务提交时,线程池中有空闲线程可以立即执行任务,无需等待线程的创建,从而提高了任务的响应速度。
    • 方便管理线程:线程池可以对线程进行统一的管理,包括线程的数量、线程的生命周期、任务的排队和调度等。可以根据系统的负载情况调整线程池的参数,优化系统性能。
  6. 当线程池的任务队列满了,并且线程数达到最大线程数时,会发生什么?
    • 当线程池的任务队列满了,并且线程数达到最大线程数时,线程池会执行拒绝策略。Java 线程池提供了 4 种默认的拒绝策略:
      • AbortPolicy(默认策略):直接抛出 RejectedExecutionException 异常,阻止系统正常运行。
      • CallerRunsPolicy:由调用线程(提交任务的线程)来执行该任务,这样可以减缓任务提交的速度。
      • DiscardPolicy:直接丢弃该任务,不做任何处理。
      • DiscardOldestPolicy:丢弃任务队列中最老的任务,然后尝试提交新任务。
  7. Spring 框架的核心是什么?
    • Spring 框架的核心是 IOC(控制反转)和 AOP(面向切面编程)。
    • IOC(控制反转):也称为依赖注入(DI),是一种将对象的创建和依赖关系的管理从代码中转移到外部容器的机制。在 Spring 中,对象的创建、组装和生命周期管理都由 Spring 容器负责,开发人员只需要在需要使用对象的地方声明依赖即可。这样可以降低代码的耦合度,提高代码的可维护性和可测试性。
    • AOP(面向切面编程):是一种在不修改原有业务逻辑的基础上,对程序进行增强的编程思想。AOP 可以将一些通用的功能(如日志记录、事务管理、权限验证等)从业务逻辑中分离出来,形成独立的切面,然后在需要的地方进行切入。这样可以提高代码的复用性和可维护性。
  8. Spring Boot 相比 Spring 有什么优势?
    • 快速搭建项目:Spring Boot 提供了大量的启动器(Starter),可以通过简单的配置快速搭建一个项目,减少了繁琐的配置文件和依赖管理。
    • 自动配置:Spring Boot 会根据项目的依赖自动进行配置,开发者只需要进行少量的自定义配置即可。例如,当项目中引入了 Spring Data JPA 和 MySQL 驱动时,Spring Boot 会自动配置数据源和 JPA 相关的配置。
    • 嵌入式服务器:Spring Boot 内置了 Tomcat、Jetty 等嵌入式服务器,不需要单独部署服务器,直接运行项目的主类即可启动应用程序。
    • 生产就绪特性:Spring Boot 提供了很多生产就绪的特性,如健康检查、指标监控、外部化配置等,方便在生产环境中对应用程序进行管理和监控。
  9. 在 MyBatis 中,#{} 和 ${} 的区别是什么?
    • #{} 是预编译处理,MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为占位符?,然后使用 PreparedStatement 进行预编译,防止 SQL 注入攻击。例如:
<select id="getUserById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>
- ${} 是字符串替换,MyBatis 在处理 ${} 时,会将 ${} 直接替换为传入的参数值。例如:
<select id="getUserByColumnName" parameterType="String" resultType="User">
    SELECT * FROM users WHERE ${columnName} = 'value'
</select>
- 由于 ${} 是直接进行字符串替换,存在 SQL 注入的风险,所以在使用时要谨慎。一般情况下,优先使用 #{},只有在需要动态传入表名、列名等无法使用占位符的情况下才使用 ${}。