《揭秘互联网大厂Java面试:从基础到进阶的核心知识点大考察》

38 阅读11分钟

第一轮面试 面试官:先从基础的 Java 核心知识问起,说说 Java 中重载和重写的区别是什么? 王铁牛:重载就是方法名相同,参数列表不同,发生在同一个类中。重写是子类重写父类的方法,方法名、参数列表、返回值类型都要一样,而且访问修饰符不能比父类更严格。 面试官:回答得不错。那讲讲 ArrayList 和 LinkedList 的区别,在业务场景中怎么选择? 王铁牛:ArrayList 是基于数组实现的,随机访问快,增删慢,适合查询多的场景。LinkedList 基于链表实现,增删快,随机访问慢,适合增删操作多的场景。 面试官:很好。接着问,HashMap 的底层数据结构是什么,在 JDK1.7 和 JDK1.8 中有什么变化? 王铁牛:JDK1.7 是数组加链表,JDK1.8 是数组加链表加红黑树,当链表长度超过 8 且数组长度大于 64 时,链表会转成红黑树。

第二轮面试 面试官:进入多线程相关问题。讲讲线程和进程的区别,在实际业务中有什么应用场景? 王铁牛:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位。线程是进程中的一个执行单元,是 CPU 调度和分派的基本单位。在 Web 服务器中,每个请求可以用一个线程处理。 面试官:不错。那多线程有什么问题,怎么解决线程安全问题? 王铁牛:多线程可能会有线程安全问题,比如多个线程同时访问共享资源。可以用 synchronized 关键字,还有 Lock 接口来解决。 面试官:那说说线程池的原理和作用,在业务中怎么合理配置线程池参数? 王铁牛:线程池就是管理一组线程,复用线程,减少线程创建和销毁的开销。参数配置嘛,核心线程数根据任务类型和硬件来,比如 CPU 密集型任务核心线程数就设为 CPU 核心数。

第三轮面试 面试官:来谈谈框架相关。Spring 框架中 IOC 和 AOP 是什么,在项目中有什么实际应用? 王铁牛:IOC 是控制反转,把对象创建和管理交给 Spring 容器。AOP 是面向切面编程,比如可以在方法执行前后加日志。 面试官:还行。那 Spring Boot 相对于 Spring 有什么优势,怎么快速搭建一个 Spring Boot 项目? 王铁牛:Spring Boot 简化了 Spring 配置,自动配置很多东西。可以用 IDE 的 Spring Initializr 快速搭建项目。 面试官:最后问下分布式相关,Dubbo 是什么,在微服务架构中有什么作用,和 Spring Cloud 有什么区别? 王铁牛:Dubbo 是一个分布式服务框架,能做服务治理。和 Spring Cloud 区别嘛,Dubbo 更专注于服务治理,Spring Cloud 功能更全面。

面试结束,面试官严肃地说:“今天的面试就到这里,你回去等通知吧。我们会综合评估所有候选人,有消息会尽快联系你。感谢你今天来参加面试,希望你之后也能继续提升自己的技术能力。”

问题答案

  1. Java 中重载和重写的区别
    • 重载(Overloading):发生在同一个类中,方法名相同,但参数列表不同(参数个数、类型、顺序不同)。返回值类型和访问修饰符可以不同。重载是一种编译时多态,编译器根据调用方法时传入的参数来决定调用哪个重载方法。例如,一个类中有 void print(int num)void print(String str) 就是重载。
    • 重写(Overriding):发生在子类与父类之间,子类重写父类的方法。方法名、参数列表、返回值类型(JDK1.5 后支持协变返回类型,即子类重写方法的返回值可以是父类方法返回值的子类)必须相同,访问修饰符不能比父类更严格(可以相同或更宽松)。重写是运行时多态,在运行时根据对象的实际类型来决定调用哪个重写方法。例如,父类有 public void run() 方法,子类重写为 public void run()
  2. ArrayList 和 LinkedList 的区别及业务场景选择
    • ArrayList:基于数组实现,内存连续。优点是随机访问速度快,因为可以通过数组下标直接定位元素,时间复杂度为 O(1)。缺点是增删操作慢,尤其是在数组中间插入或删除元素时,需要移动大量元素,时间复杂度为 O(n)。适用于查询频繁,增删操作较少的场景,如数据展示列表。
    • LinkedList:基于链表实现,每个节点包含数据和指向前一个及后一个节点的引用。优点是增删操作快,只需修改节点的引用,时间复杂度为 O(1)。缺点是随机访问慢,需要从链表头或尾开始遍历,时间复杂度为 O(n)。适用于增删操作频繁,查询操作较少的场景,如实现栈或队列。
  3. HashMap 的底层数据结构及 JDK1.7 和 JDK1.8 的变化
    • JDK1.7:底层是数组加链表。数组的每个元素是一个链表头节点,当发生哈希冲突时,新元素以头插法插入到链表中。这种结构在哈希冲突严重时,链表会很长,导致查询性能下降,时间复杂度最坏为 O(n)。
    • JDK1.8:底层是数组加链表加红黑树。当链表长度超过 8 且数组长度大于 64 时,链表会转成红黑树,以提高查询性能。红黑树的查询时间复杂度为 O(logn)。当红黑树节点数小于 6 时,又会退化为链表。这样在哈希冲突较严重时,也能保持较好的查询性能。
  4. 线程和进程的区别及实际业务应用场景
    • 进程:是程序的一次执行过程,是系统进行资源分配和调度的基本单位。每个进程都有独立的内存空间,包括代码段、数据段、堆、栈等。进程间通信相对复杂,如管道、消息队列、共享内存等。例如,一个 Web 服务器程序就是一个进程,它可以处理多个用户请求。
    • 线程:是进程中的一个执行单元,是 CPU 调度和分派的基本单位。线程共享进程的资源,如内存空间、文件描述符等。线程间通信相对简单,如通过共享变量。在 Web 服务器中,每个用户请求可以用一个线程处理,这样可以提高并发处理能力。
  5. 多线程问题及解决线程安全问题的方法
    • 多线程问题:主要是线程安全问题,当多个线程同时访问共享资源时,可能会出现数据不一致的情况。例如,多个线程同时对一个共享变量进行读写操作,可能导致数据错误。
    • 解决方法
      • synchronized 关键字:可以修饰方法或代码块。修饰方法时,整个方法成为同步方法,同一时间只有一个线程能执行该方法。修饰代码块时,只有进入该代码块的线程会被同步。它通过监视器锁(monitor)来实现线程同步,原理是基于对象头中的 Mark Word。
      • Lock 接口:提供了比 synchronized 更灵活的锁控制,如可中断的锁获取、公平锁等。常用的实现类有 ReentrantLock。使用 Lock 时,需要手动获取锁和释放锁,通过 lock() 方法获取锁,unlock() 方法释放锁。
  6. 线程池的原理、作用及参数配置
    • 原理:线程池管理一组工作线程,当有任务提交时,线程池会从线程队列中取出一个空闲线程来执行任务。如果线程队列已满,任务会根据不同的拒绝策略进行处理。
    • 作用:复用线程,减少线程创建和销毁的开销,提高系统性能和响应速度。控制线程数量,避免过多线程导致系统资源耗尽。
    • 参数配置
      • 核心线程数(corePoolSize):线程池中常驻的线程数。对于 CPU 密集型任务,核心线程数一般设为 CPU 核心数;对于 I/O 密集型任务,核心线程数可以适当增大,因为 I/O 操作会使线程等待,需要更多线程来利用 CPU 资源。
      • 最大线程数(maximumPoolSize):线程池允许创建的最大线程数。当任务队列已满且核心线程都在忙碌时,线程池会创建新线程,直到达到最大线程数。
      • 任务队列(workQueue):用于存放等待执行的任务。常用的任务队列有 ArrayBlockingQueue、LinkedBlockingQueue 等。
      • 线程存活时间(keepAliveTime):当线程数大于核心线程数时,多余的空闲线程的存活时间。超过这个时间,空闲线程会被销毁。
  7. Spring 框架中 IOC 和 AOP 及实际应用
    • IOC(控制反转):将对象的创建和管理交给 Spring 容器,而不是由应用程序自己创建对象。通过依赖注入(DI)的方式,Spring 容器将对象所需的依赖注入到对象中。例如,一个 Service 类依赖于一个 Dao 类,在传统方式中需要在 Service 类中手动创建 Dao 对象,而在 Spring 中,Spring 容器会自动创建 Dao 对象并注入到 Service 类中。这样可以降低组件之间的耦合度,提高代码的可维护性和可测试性。
    • AOP(面向切面编程):将一些通用的功能(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,形成一个个切面。这些切面可以在不修改原有业务代码的情况下,在方法执行前后、异常处理等位置织入通用功能。例如,在方法执行前记录日志,在方法执行后进行事务提交等。
  8. Spring Boot 相对于 Spring 的优势及快速搭建项目方法
    • 优势
      • 简化配置:Spring Boot 提供了自动配置功能,大大减少了 Spring 项目中繁琐的 XML 配置或 Java 配置。
      • 快速开发:内置了很多常用的依赖和插件,如 Tomcat、Spring MVC 等,开箱即用,加快项目开发速度。
      • 微服务友好:方便构建微服务架构,支持各种微服务组件,如 Eureka、Zuul 等。
    • 快速搭建项目方法
      • 使用 Spring Initializr:在 IDE(如 IntelliJ IDEA、Eclipse 等)中,通过 Spring Initializr 可以快速生成一个 Spring Boot 项目骨架。只需选择项目的基本信息,如项目坐标、依赖等,IDE 会自动生成项目结构和相关配置文件。
      • Maven 或 Gradle 构建:也可以通过在命令行使用 Maven 或 Gradle 命令来创建项目。例如,使用 Maven 命令 mvn archetype:generate -DgroupId=com.example -DartifactId=myproject -DarchetypeArtifactId=maven -archetype - quickstart -DinteractiveMode=false,然后将生成的项目转换为 Spring Boot 项目,添加 Spring Boot 相关依赖和配置。
  9. Dubbo 及在微服务架构中的作用和与 Spring Cloud 的区别
    • Dubbo:是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及服务治理方案。
    • 在微服务架构中的作用
      • 服务注册与发现:Dubbo 可以将服务注册到注册中心(如 Zookeeper),其他服务可以从注册中心获取服务地址,实现服务的动态发现。
      • 负载均衡:在调用服务时,Dubbo 提供多种负载均衡策略,如随机、轮询、最少活跃调用数等,将请求均匀分配到多个服务实例上。
      • 服务治理:包括服务降级、服务容错、服务监控等功能,保证微服务架构的稳定性和可靠性。
    • 与 Spring Cloud 的区别
      • 功能定位:Dubbo 更专注于服务治理,如服务的注册与发现、负载均衡、远程调用等。Spring Cloud 功能更全面,涵盖了服务治理、配置管理、熔断器、网关等多个方面,是一个完整的微服务解决方案。
      • 技术选型:Dubbo 的 RPC 调用基于 Netty 等高性能网络框架,性能较高。Spring Cloud 更多地依赖于 HTTP 协议和 RESTful 风格的接口,灵活性较高,但性能相对较低。
      • 生态系统:Spring Cloud 依托 Spring 生态,有丰富的组件和广泛的社区支持。Dubbo 也有自己的社区,但生态相对 Spring Cloud 较小。