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

53 阅读10分钟

第一轮面试 面试官:先从基础的Java核心知识问起。Java中重载和重写的区别是什么? 王铁牛:重载就是方法名相同,参数列表不同;重写是子类重写父类的方法,方法名、参数列表和返回值都得一样,而且访问修饰符不能比父类更严格。 面试官:回答得不错。那说说Java中多态是如何实现的? 王铁牛:通过继承、重写和向上转型来实现,父类引用指向子类对象,调用方法时会根据实际对象类型来执行对应的方法。 面试官:很好。那ArrayList和HashMap在存储结构上有什么不同? 王铁牛:ArrayList是基于数组的,有序可重复;HashMap是基于哈希表的,无序键值对,通过哈希算法存储和查找。

第二轮面试 面试官:接下来聊聊JUC和多线程。线程池有哪些核心参数? 王铁牛:嗯……有核心线程数、最大线程数,还有……还有队列容量吧。 面试官:还算可以。那说说线程池的工作原理,比如任务是怎么分配的? 王铁牛:就是先看核心线程有没有满,满了就放队列里,队列满了再看能不能创建新线程到最大线程数,要是还不行就拒绝任务。 面试官:那在高并发场景下,使用线程池有什么好处? 王铁牛:能复用线程,减少创建和销毁线程的开销,提高性能,还能控制并发数量。

第三轮面试 面试官:最后问问框架相关的。Spring的IOC和AOP是什么? 王铁牛:IOC是控制反转,把对象创建和管理交给Spring容器;AOP是面向切面编程,能在不修改原有代码基础上增加功能,像日志记录啥的。 面试官:那Spring Boot相比Spring有什么优势? 王铁牛:它简化了Spring的配置,能快速搭建项目,内置了很多依赖,开箱即用。 面试官:Dubbo在分布式系统中有什么作用? 王铁牛:嗯……好像是做服务治理的,能实现服务的注册、发现和调用。

面试总结:从整体面试情况来看,你在一些基础的Java核心知识方面回答得较为准确,像重载重写、多态以及ArrayList和HashMap的区别,展现出了你对基础知识的掌握。在JUC和多线程部分,对于线程池的核心参数和基本工作原理也有一定的理解。然而,在面对一些更深入的问题,比如框架相关的Dubbo在分布式系统中的具体作用等,回答得不是特别清晰和全面。我们后续会综合评估所有面试者的情况,你先回家等通知,无论结果如何,我们都会在一周内给你回复。

问题答案

  1. Java中重载和重写的区别
    • 重载(Overloading):发生在同一个类中,方法名相同,但参数列表不同(参数个数、类型、顺序不同)。与返回值类型和访问修饰符无关。例如,一个类中有void add(int a, int b)int add(int a, int b, int c)就是方法重载。它是一种编译时多态,在编译阶段就确定调用哪个方法。
    • 重写(Overriding):发生在子类与父类之间,子类重写父类的方法。要求方法名、参数列表、返回值类型(Java 5及之后,返回值可以是父类返回值的子类)必须相同,访问修饰符不能比父类更严格(可以相同或更宽松)。比如父类有public void show(),子类重写为public void show()。重写是运行时多态,在运行时根据对象的实际类型确定调用哪个方法。
  2. Java中多态是如何实现的
    • 继承:子类继承父类,获得父类的属性和方法,为多态提供了基础结构。
    • 重写:子类重写父类的方法,实现不同的行为。
    • 向上转型:父类引用指向子类对象,如Animal animal = new Dog();(假设Dog继承自Animal)。在调用方法时,会根据实际对象(这里是Dog对象)的类型来执行对应的重写方法,实现多态。
  3. ArrayList和HashMap在存储结构上有什么不同
    • ArrayList:基于动态数组实现。它有序存储元素,可以通过索引快速访问元素。当元素数量超过数组容量时,会自动扩容。例如ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b");,元素按添加顺序存储。
    • HashMap:基于哈希表实现,采用“数组 + 链表(JDK 1.8后引入红黑树优化)”的数据结构。通过键的哈希值确定存储位置,以键值对形式存储数据。键不能重复,值可以重复。例如HashMap<String, Integer> map = new HashMap<>(); map.put("one", 1);,通过计算“one”的哈希值找到存储位置。
  4. 线程池有哪些核心参数
    • 核心线程数(corePoolSize):线程池中常驻的线程数,即使这些线程处于空闲状态,也不会被销毁(除非设置了allowCoreThreadTimeOut为true)。
    • 最大线程数(maximumPoolSize):线程池允许创建的最大线程数。当任务队列满了且核心线程都在忙碌时,会创建新线程直到达到最大线程数。
    • 队列容量(workQueue):用于存储等待执行的任务的队列。常见的队列类型有ArrayBlockingQueue(有界数组队列)、LinkedBlockingQueue(无界链表队列)等。
    • 线程存活时间(keepAliveTime):当线程数大于核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
    • 时间单位(unit):keepAliveTime的时间单位,如TimeUnit.SECONDS(秒)。
    • 拒绝策略(RejectedExecutionHandler):当任务队列已满且线程数达到最大线程数时,新任务的处理策略。常见的有AbortPolicy(直接抛出异常)、CallerRunsPolicy(将任务交给调用者线程执行)、DiscardPolicy(丢弃任务)、DiscardOldestPolicy(丢弃队列中最老的任务,尝试提交新任务)。
  5. 线程池的工作原理,比如任务是怎么分配的
    • 当有新任务提交到线程池时,首先判断核心线程数是否已满。如果未满,创建新的核心线程来执行任务。
    • 如果核心线程数已满,任务会被放入任务队列(workQueue)中等待。
    • 如果任务队列也已满,再判断当前线程数是否达到最大线程数。若未达到,创建新的非核心线程来执行任务。
    • 如果线程数已达到最大线程数,根据设置的拒绝策略来处理新任务。
  6. 在高并发场景下,使用线程池有什么好处
    • 减少线程创建和销毁开销:线程的创建和销毁是比较消耗资源的操作。线程池可以复用已创建的线程,避免频繁创建和销毁线程,提高系统性能。
    • 控制并发数量:通过设置核心线程数和最大线程数,可以控制系统的并发度,防止过多线程导致系统资源耗尽,如CPU过度占用、内存溢出等。
    • 提高响应速度:由于不需要等待线程创建,任务可以更快地得到执行,提高了系统的响应速度。
    • 统一管理线程:线程池提供了一种统一管理线程的方式,方便进行监控、调优等操作。
  7. Spring的IOC和AOP是什么
    • IOC(Inversion of Control,控制反转):将对象的创建和管理控制权从应用程序代码转移到Spring容器。应用程序只需要使用对象,而不需要关心对象的创建过程。例如,在传统Java开发中,我们可能会在代码中使用new关键字创建对象,而在Spring中,通过配置(XML或注解)让Spring容器创建和管理对象。Spring通过依赖注入(Dependency Injection,DI)来实现IOC,常见的依赖注入方式有构造函数注入、Setter方法注入和字段注入。
    • AOP(Aspect - Oriented Programming,面向切面编程):是一种编程范式,旨在将横切关注点(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,以提高代码的可维护性和可复用性。在Spring中,通过切面(Aspect)定义横切逻辑,切入点(Pointcut)定义在哪些连接点(Joinpoint,如方法调用、异常抛出等)应用切面逻辑,通知(Advice,如前置通知、后置通知、环绕通知等)定义在连接点执行的具体操作。例如,通过AOP可以在方法执行前记录日志,而不需要在每个业务方法中重复编写日志记录代码。
  8. Spring Boot相比Spring有什么优势
    • 简化配置:Spring Boot采用“约定大于配置”的原则,默认提供了很多合理的配置,大大减少了Spring应用中繁琐的XML配置或Java配置代码。例如,使用Spring Boot创建一个Web应用,只需要很少的配置就能快速搭建起来,而传统Spring需要配置大量的Servlet、DispatcherServlet等。
    • 快速开发:内置了大量的Starter依赖,开发者只需要引入相关的Starter,Spring Boot就能自动配置好相应的功能。比如引入spring - boot - starter - web就能快速搭建一个Web项目,包含了Tomcat服务器、Spring MVC等相关依赖和配置。
    • 生产就绪:提供了很多生产环境所需的特性,如健康检查、指标监控、外部化配置等。可以方便地集成监控工具,查看应用的运行状态。
    • 开箱即用:对于常见的应用场景,如数据库连接、消息队列等,Spring Boot都提供了简单易用的集成方式,降低了开发门槛。
  9. Dubbo在分布式系统中有什么作用
    • 服务注册与发现:Dubbo提供了服务注册中心(如Zookeeper、Nacos等),服务提供者将自己提供的服务注册到注册中心,服务消费者从注册中心获取服务地址。这样,消费者不需要硬编码服务提供者的地址,提高了系统的可维护性和扩展性。例如,当服务提供者的地址发生变化时,消费者可以从注册中心获取最新地址。
    • 服务调用:支持多种远程调用协议,如Dubbo协议、HTTP协议等,实现服务之间的远程调用。它对调用过程进行了封装,提供了高性能、透明化的远程方法调用。
    • 负载均衡:当有多个服务提供者提供相同服务时,Dubbo可以在服务消费者调用时进行负载均衡,将请求均匀分配到各个服务提供者,提高系统的整体性能和可用性。常见的负载均衡策略有随机、轮询、最少活跃调用数等。
    • 服务治理:包括服务降级、服务容错、服务限流等功能。在服务提供者出现故障或压力过大时,通过服务降级可以返回一个默认值,保证系统的基本可用性;服务容错机制可以处理调用过程中的异常情况;服务限流可以控制单位时间内的请求数量,防止服务被压垮。