互联网大厂 Java 面试:核心知识、框架与中间件大考验
严肃的面试官坐在桌前,面前放着求职者王铁牛的简历,王铁牛略显紧张地坐在对面。面试正式开始。
第一轮提问 面试官:首先问几个 Java 核心知识的问题。Java 中基本数据类型有哪些? 王铁牛:Java 的基本数据类型有 byte、short、int、long、float、double、char、boolean。 面试官:回答得不错。那 String 类为什么是不可变的,有什么好处? 王铁牛:因为 String 类是用 final 修饰的,不可变的好处是可以提高安全性,避免被意外修改,还能实现字符串常量池,节省内存。 面试官:很好。那在 Java 里,重载和重写的区别是什么? 王铁牛:重载是在同一个类中,方法名相同但参数列表不同;重写是子类重写父类的方法,方法名、参数列表和返回值都要一样。
第二轮提问 面试官:接下来聊聊 JUC、多线程和线程池的问题。什么是 JUC,它包含哪些主要的类和接口? 王铁牛:JUC 就是 java.util.concurrent 包,里面有像 ExecutorService 接口、ThreadPoolExecutor 类、CountDownLatch 类这些。 面试官:不错。那创建线程有哪几种方式,各自的优缺点是什么? 王铁牛:创建线程有继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池这几种方式。继承 Thread 类的优点是简单,缺点是不能再继承其他类;实现 Runnable 接口可以避免单继承的局限;实现 Callable 接口可以有返回值;线程池可以复用线程,提高性能。 面试官:很好。那线程池的核心参数有哪些,它们分别有什么作用? 王铁牛:线程池的核心参数有 corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory 和 handler。corePoolSize 是核心线程数,maximumPoolSize 是最大线程数,keepAliveTime 是线程空闲时的存活时间,unit 是时间单位,workQueue 是任务队列,threadFactory 是线程工厂,handler 是任务拒绝策略。
第三轮提问 面试官:现在问一些关于框架和中间件的问题。Spring 框架的核心特性有哪些? 王铁牛:Spring 框架的核心特性有 IoC(控制反转)和 AOP(面向切面编程)。 面试官:那 Spring Boot 相比 Spring 有什么优势? 王铁牛:Spring Boot 相比 Spring 有很多优势,它可以快速搭建项目,自动配置,减少了很多繁琐的配置文件。 面试官:MyBatis 是如何实现数据库操作的? 王铁牛:嗯……就是通过 XML 文件或者注解来定义 SQL 语句,然后和 Java 对象进行映射,就可以操作数据库了。 面试官:Dubbo 是什么,它有什么作用? 王铁牛:Dubbo 是一个分布式服务框架,它可以实现服务的注册和发现,提高系统的可扩展性和性能。 面试官:RabbitMQ、xxl - job 和 Redis 在项目里一般都有什么应用场景? 王铁牛:RabbitMQ 可以用于消息队列,实现异步通信和系统解耦;xxl - job 是分布式任务调度平台,用于定时任务;Redis 可以作为缓存,提高系统的访问速度。
面试官:好的,今天的面试就到这里,你回家等通知吧。我们会尽快给你反馈。
答案详解
- Java 基本数据类型:Java 中有 8 种基本数据类型,可分为 4 类。整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节);浮点类型:float(4 字节)、double(8 字节);字符类型:char(2 字节);布尔类型:boolean(true 或 false)。
- String 类不可变的原因及好处:String 类使用 final 修饰,其内部的字符数组也是 final 的,所以不可变。好处有:安全性,例如在多线程环境中,不可变对象不会被意外修改;实现字符串常量池,相同的字符串可以共享内存,节省空间。
- 重载和重写的区别:重载是在同一个类中,方法名相同但参数列表不同(参数个数、类型、顺序不同),与返回值类型无关;重写是子类重写父类的方法,方法名、参数列表和返回值类型都要相同(返回值类型可以是父类返回值类型的子类,这叫协变返回类型),重写时不能降低方法的访问权限。
- JUC 及其主要类和接口:JUC(java.util.concurrent)是 Java 并发编程的核心包。主要类和接口有:ExecutorService 是线程池的核心接口,用于管理线程和执行任务;ThreadPoolExecutor 是线程池的具体实现类;CountDownLatch 是一个同步工具类,允许一个或多个线程等待其他线程完成操作。
- 创建线程的方式及优缺点:
- 继承 Thread 类:优点是简单,直接继承并重写 run 方法即可;缺点是 Java 是单继承,继承了 Thread 类就不能再继承其他类。
- 实现 Runnable 接口:优点是可以避免单继承的局限,一个类可以实现多个接口;缺点是没有返回值。
- 实现 Callable 接口:优点是可以有返回值,通过 Future 可以获取线程执行的结果;缺点是使用相对复杂。
- 使用线程池:优点是可以复用线程,减少线程创建和销毁的开销,提高性能;缺点是需要合理配置线程池参数。
- 线程池的核心参数及作用:
- corePoolSize:核心线程数,线程池初始化时创建的线程数量。
- maximumPoolSize:最大线程数,线程池允许创建的最大线程数量。
- keepAliveTime:线程空闲时的存活时间,当线程空闲时间超过该值,会被销毁。
- unit:时间单位,如 TimeUnit.SECONDS 表示秒。
- workQueue:任务队列,用于存储等待执行的任务。常见的有 ArrayBlockingQueue、LinkedBlockingQueue 等。
- threadFactory:线程工厂,用于创建线程,可以自定义线程的名称、优先级等。
- handler:任务拒绝策略,当线程池达到最大线程数且任务队列已满时,新任务会被拒绝。常见的拒绝策略有 AbortPolicy(直接抛出异常)、CallerRunsPolicy(由调用线程执行任务)等。
- Spring 框架的核心特性:
- IoC(控制反转):将对象的创建和依赖关系的管理交给 Spring 容器,而不是由对象本身来创建和管理,降低了代码的耦合度。
- AOP(面向切面编程):可以在不修改原有代码的基础上,对程序进行增强,例如日志记录、事务管理等。
- Spring Boot 相比 Spring 的优势:
- 快速搭建项目:Spring Boot 提供了很多启动器依赖,通过简单的配置就可以快速搭建一个项目。
- 自动配置:Spring Boot 会根据项目的依赖自动进行配置,减少了大量的配置文件。
- 嵌入式服务器:可以将服务器(如 Tomcat、Jetty)嵌入到项目中,方便开发和部署。
- MyBatis 实现数据库操作的方式:MyBatis 通过 XML 文件或者注解来定义 SQL 语句,然后将 SQL 语句与 Java 对象进行映射。XML 文件中可以定义 SQL 语句、参数映射和结果映射;注解方式可以直接在接口方法上使用注解来定义 SQL 语句。MyBatis 会根据映射关系将 Java 对象的数据传递给 SQL 语句,执行 SQL 操作后将结果映射为 Java 对象。
- Dubbo 的作用:Dubbo 是一个分布式服务框架,主要用于实现服务的注册和发现、远程调用和负载均衡。服务提供者将服务注册到注册中心,服务消费者从注册中心获取服务提供者的地址,然后通过远程调用的方式调用服务。Dubbo 还支持多种负载均衡策略,如随机、轮询等,提高系统的性能和可扩展性。
- RabbitMQ、xxl - job 和 Redis 的应用场景:
- RabbitMQ:用于消息队列,实现异步通信和系统解耦。例如,在电商系统中,用户下单后可以将订单信息发送到 RabbitMQ 队列,由其他服务异步处理订单,提高系统的响应速度。
- xxl - job:是分布式任务调度平台,用于定时任务的管理和执行。可以在不同的服务器上分布式执行定时任务,提高任务执行的效率和可靠性。
- Redis:作为缓存,提高系统的访问速度。例如,将经常访问的数据存储在 Redis 中,当用户访问数据时,先从 Redis 中获取,如果没有再从数据库中获取,减少数据库的访问压力。还可以用于分布式锁、排行榜等场景。