在互联网大厂的一间安静面试室内,严肃的面试官正对面坐着略显紧张的求职者王铁牛,一场对 Java 技术知识的考验即将展开。
第一轮面试 面试官:我们先从 Java 核心知识开始。你能说一下 Java 的基本数据类型有哪些吗? 王铁牛:可以,Java 的基本数据类型有 byte、short、int、long、float、double、char 和 boolean。 面试官:回答得不错。那你说说自动装箱和拆箱是怎么回事? 王铁牛:自动装箱就是把基本数据类型转换成对应的包装类,拆箱就是把包装类转换成基本数据类型。比如 Integer i = 10 就是自动装箱,int j = i 就是拆箱。 面试官:很好。那在 Java 中,String 是基本数据类型吗?如果不是,它有什么特点? 王铁牛:String 不是基本数据类型,它是一个类。String 的特点是一旦创建,其值不能被改变,因为它是不可变的,每次对 String 进行操作都会生成一个新的 String 对象。
第二轮面试 面试官:接下来谈谈 JUC 和多线程。什么是线程安全?如何实现线程安全? 王铁牛:线程安全就是当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。可以使用 synchronized 关键字或者 JUC 包下的锁来实现线程安全。 面试官:那你说一下 synchronized 和 ReentrantLock 的区别。 王铁牛:呃……这个嘛,好像都能实现同步,具体区别我有点说不太清楚。 面试官:那线程池你了解吗?线程池有哪些核心参数? 王铁牛:线程池我知道,核心参数有 corePoolSize、maximumPoolSize、keepAliveTime、unit 和 workQueue 等。corePoolSize 是核心线程数,maximumPoolSize 是最大线程数。 面试官:那当提交的任务数超过线程池的最大线程数时,会发生什么? 王铁牛:这个……我不太确定,好像会有一些处理策略,但具体的我记不太清了。
第三轮面试 面试官:我们再聊聊框架相关的。Spring 的 IOC 和 AOP 是什么? 王铁牛:IOC 是控制反转,就是把对象的创建和依赖关系的管理交给 Spring 容器,而不是由对象自己来创建和管理。AOP 是面向切面编程,它可以在不修改原有代码的情况下,对程序进行增强,比如实现日志记录、事务管理等功能。 面试官:Spring Boot 相对于 Spring 有什么优势? 王铁牛:Spring Boot 可以快速搭建项目,它有很多默认配置,能减少开发者的配置工作,还能实现自动配置,提高开发效率。 面试官:MyBatis 中 #{} 和 {} 的区别是什么? **王铁牛**:呃……这个我知道一点,好像 #{} 能防止 SQL 注入,{} 就是直接替换,但是具体原理我不太清楚。 面试官:Dubbo 是做什么的?它的工作原理是什么? 王铁牛:Dubbo 是一个分布式服务框架,能实现服务的远程调用。工作原理嘛,我就说不太明白了。
面试结束后,面试官看着王铁牛说:“今天的面试就到这里,你对一些基础问题回答得还可以,展现出了一定的知识储备,但对于一些深入的问题,回答得不够清晰和完整。你先回家等通知吧,后续如果有结果我们会及时联系你。”
以下是问题的详细答案:
- Java 的基本数据类型有哪些:Java 的基本数据类型分为 4 类 8 种。整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节);浮点类型:float(4 字节)、double(8 字节);字符类型:char(2 字节);布尔类型:boolean(理论上 1 位,但 JVM 通常按 1 字节处理)。
- 自动装箱和拆箱是怎么回事:自动装箱是 Java 编译器在基本数据类型和对应的包装类之间进行的自动转换。例如,当把一个基本数据类型赋值给对应的包装类时,编译器会自动调用包装类的 valueOf 方法进行装箱操作。拆箱则是把包装类对象转换成基本数据类型,编译器会自动调用包装类的 xxxValue 方法,如 intValue()、doubleValue() 等。
- String 是基本数据类型吗?如果不是,它有什么特点:String 不是基本数据类型,而是一个类。它的特点有:不可变性,即 String 对象一旦创建,其值不能被改变,这是因为 String 类被 final 修饰,其内部的字符数组也是 final 的。每次对 String 进行操作(如拼接、替换等)都会生成一个新的 String 对象。String 类重写了 equals 方法和 hashCode 方法,用于比较字符串的内容是否相等。
- 什么是线程安全?如何实现线程安全:线程安全是指在多线程环境下,一个对象或方法可以被多个线程同时访问而不会产生数据不一致或其他错误。实现线程安全的方法有:使用 synchronized 关键字,它可以修饰方法或代码块,保证同一时刻只有一个线程可以访问被修饰的代码;使用 JUC 包下的锁,如 ReentrantLock,它提供了更灵活的锁机制,支持公平锁和非公平锁;使用原子类,如 AtomicInteger、AtomicLong 等,它们基于 CAS(Compare - And - Swap)操作实现线程安全。
- synchronized 和 ReentrantLock 的区别:synchronized 是 Java 中的关键字,是内置的锁机制;ReentrantLock 是 JUC 包下的一个类。synchronized 是隐式锁,会自动释放锁;ReentrantLock 需要手动加锁和解锁,通过 lock() 和 unlock() 方法。ReentrantLock 支持公平锁和非公平锁,而 synchronized 只支持非公平锁。ReentrantLock 可以响应中断,而 synchronized 不能。
- 线程池有哪些核心参数:线程池的核心参数有 corePoolSize(核心线程数),表示线程池长期维持的线程数量;maximumPoolSize(最大线程数),即线程池允许的最大线程数量;keepAliveTime(线程空闲存活时间),当线程池中的线程数量超过核心线程数时,多余的空闲线程在多长时间内会被销毁;unit(时间单位),用于指定 keepAliveTime 的时间单位;workQueue(工作队列),用于存储等待执行的任务;threadFactory(线程工厂),用于创建线程;handler(任务拒绝策略),当工作队列满且线程池中的线程数量达到最大线程数时,对新提交的任务的处理策略。
- 当提交的任务数超过线程池的最大线程数时,会发生什么:当提交的任务数超过线程池的最大线程数时,会触发任务拒绝策略。常见的拒绝策略有:AbortPolicy(默认策略),直接抛出 RejectedExecutionException 异常;CallerRunsPolicy,由提交任务的线程来执行该任务;DiscardPolicy,直接丢弃该任务,不做任何处理;DiscardOldestPolicy,丢弃工作队列中最老的任务,然后尝试重新提交新任务。
- Spring 的 IOC 和 AOP 是什么:IOC(控制反转)是 Spring 的核心思想之一,它将对象的创建和依赖关系的管理从对象本身转移到 Spring 容器中。通过 Spring 容器来创建和管理对象,对象之间的依赖关系由容器来注入,从而降低了对象之间的耦合度。AOP(面向切面编程)是一种编程范式,它允许开发者在不修改原有代码的情况下,对程序进行增强。AOP 主要通过切面(Aspect)、通知(Advice)和连接点(Join Point)等概念来实现,常见的应用场景有日志记录、事务管理、权限验证等。
- Spring Boot 相对于 Spring 有什么优势:Spring Boot 简化了 Spring 项目的搭建和配置过程。它提供了大量的 Starter 依赖,开发者只需要引入相应的 Starter 依赖,Spring Boot 就会自动进行配置,减少了繁琐的 XML 配置文件。Spring Boot 内置了 Tomcat、Jetty 等服务器,方便开发者快速启动项目。Spring Boot 还提供了 Actuator 功能,方便对应用进行监控和管理。
- **MyBatis 中 #{} 和 {} 的区别是什么**:#{} 是预编译处理,MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 占位符,然后使用 PreparedStatement 进行参数设置,这样可以防止 SQL 注入。{} 是直接替换,MyBatis 在处理 {} 直接替换为参数的值,不会进行预编译,因此可能会存在 SQL 注入的风险。通常情况下,对于需要传入参数的情况,建议使用 #{};而对于一些需要动态传入表名、列名等情况,可以使用 ${},但要注意对传入的值进行严格的校验。
- Dubbo 是做什么的?它的工作原理是什么:Dubbo 是一个高性能、轻量级的分布式服务框架,主要用于实现服务的远程调用和服务治理。其工作原理如下:服务提供者(Provider)将自己提供的服务注册到注册中心(Registry);服务消费者(Consumer)从注册中心订阅自己需要的服务;当服务消费者需要调用服务时,会从注册中心获取服务提供者的地址信息,然后通过远程调用协议(如 Dubbo 协议、HTTP 协议等)调用服务提供者的服务;监控中心(Monitor)负责收集服务的调用信息,如调用次数、调用时间等,用于服务的监控和统计。