《互联网大厂Java求职者面试:核心知识大考验》

52 阅读7分钟

面试官:请简要介绍一下Java核心知识,比如面向对象的三大特性。

王铁牛:这个我知道,面向对象的三大特性是封装、继承和多态。封装就是把对象的属性和方法封装起来,对外提供统一的接口;继承可以让子类继承父类的属性和方法;多态则是同一个方法可以根据对象的不同类型表现出不同的行为。

面试官:不错,回答得很准确。那再说说JUC包下的常用类有哪些。

王铁牛:JUC包下有很多常用类啊,比如CountDownLatch、CyclicBarrier、Semaphore这些。

面试官:很好。接下来问几个关于JVM的问题,类加载的过程分为哪几个阶段?

王铁牛:类加载过程分为加载、验证、准备、解析、初始化这几个阶段。

第一轮结束。

面试官:多线程中,如何创建线程?

王铁牛:可以通过继承Thread类或者实现Runnable接口来创建线程。

面试官:线程池有哪些参数,分别有什么作用?

王铁牛:线程池有corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler这些参数。corePoolSize是核心线程数,maximumPoolSize是最大线程数,keepAliveTime是线程池中的线程在超出corePoolSize后,多余的空闲线程的存活时间,unit是keepAliveTime的时间单位,workQueue是任务队列,threadFactory是线程工厂,handler是拒绝策略。

面试官:HashMap的底层数据结构是什么?

王铁牛:HashMap底层是数组+链表+红黑树的数据结构。

第二轮结束。

面试官:Spring的核心特性有哪些?

王铁牛:Spring的核心特性有依赖注入、面向切面编程、IoC容器等。

面试官:Spring Boot的自动配置原理是什么?

王铁牛:Spring Boot的自动配置原理就是通过@EnableAutoConfiguration注解,利用SpringFactoriesLoader加载所有的自动配置类,根据条件判断来决定是否启用某个配置。

面试官:MyBatis的#{}和${}有什么区别?

王铁牛:#{}会进行预编译,防止SQL注入,${}不会进行预编译,可能会有SQL注入风险。

第三轮结束。

面试结束,面试官表示会让王铁牛回家等通知。

答案:

  1. 面向对象的三大特性:
    • 封装:将对象的属性和方法包装起来,对外提供统一的访问接口,提高了代码的安全性和可维护性。例如,一个类中的属性可以用private修饰,通过public的getter和setter方法来访问和修改。
    • 继承:子类继承父类的属性和方法,实现代码的复用。比如,一个父类有一些通用的方法,子类可以继承这些方法并根据自身需求进行扩展。
    • 多态:同一个方法根据对象的不同类型表现出不同的行为。比如,一个父类引用可以指向子类对象,调用同一个方法时会执行子类的具体实现。
  2. JUC包下的常用类:
    • CountDownLatch:用于协调多个线程之间的同步,它允许一个或多个线程等待其他线程完成一组操作。例如,主线程可以等待多个子线程都执行完任务后再继续执行。
    • CyclicBarrier:它可以让一组线程互相等待,直到所有线程都到达某个屏障点。之后,这些线程可以继续执行。比如,在一个多线程协作的场景中,所有线程都需要完成各自的一部分任务后,才能一起进行下一步操作。
    • Semaphore:信号量,用于控制同时访问某个资源的线程数量。例如,限制数据库连接池的最大连接数。
  3. 类加载的过程:
    • 加载:将类的字节码文件加载到内存中。
    • 验证:检查字节码文件的格式、语义等是否正确。
    • 准备:为类的静态变量分配内存并设置初始值。
    • 解析:将符号引用转换为直接引用。
    • 初始化:执行类的静态代码块,为静态变量赋值等操作。
  4. 创建线程的方式:
    • 继承Thread类:通过继承Thread类并重写run方法来创建线程。
    • 实现Runnable接口:实现Runnable接口的run方法,然后将其作为参数传递给Thread类的构造函数来创建线程。
  5. 线程池的参数及作用:
    • corePoolSize:核心线程数,线程池在创建后,首先会创建corePoolSize个线程来处理任务。
    • maximumPoolSize:最大线程数,当任务队列满了且线程数小于maximumPoolSize时,会创建新的线程来处理任务,直到线程数达到maximumPoolSize。
    • keepAliveTime:线程池中的线程在超出corePoolSize后,多余的空闲线程的存活时间。
    • unit:keepAliveTime的时间单位。
    • workQueue:任务队列,用于存放提交到线程池但尚未被处理的任务。
    • threadFactory:线程工厂,用于创建线程,可自定义线程的名称、优先级等。
    • handler:拒绝策略,当线程池的线程数达到maximumPoolSize且任务队列已满时,会调用handler来处理新提交的任务,常见的拒绝策略有AbortPolicy(直接抛出异常)、CallerRunsPolicy(调用者线程处理任务)、DiscardPolicy(丢弃新提交的任务)、DiscardOldestPolicy(丢弃任务队列中最旧的任务)。
  6. HashMap的底层数据结构:
    • HashMap底层是数组+链表+红黑树的数据结构。初始时,HashMap创建一个长度为16的数组。当向HashMap中插入键值对时,首先通过key的hashCode计算出哈希值,然后通过哈希值与数组长度取模得到数组的索引位置。如果该位置为空,则直接插入新的键值对。如果该位置不为空,就会发生哈希冲突,此时会将新的键值对以链表的形式添加到该位置的链表中。当链表长度达到8时(JDK 1.8及以后),链表会转换为红黑树,以提高查找效率。
  7. Spring的核心特性:
    • 依赖注入:通过容器将依赖对象注入到需要的组件中,降低组件之间的耦合度。例如,一个类需要使用另一个类的功能,通过依赖注入可以方便地获取到该依赖类的实例。
    • 面向切面编程(AOP):通过预编译方式和运行期动态代理实现程序功能的统一维护。比如,在不修改业务逻辑代码的情况下,实现日志记录、事务管理等功能。
    • IoC容器:控制反转容器,负责创建、配置和管理对象之间的依赖关系。容器负责对象的创建和生命周期管理,对象只需要声明依赖,而不需要自己去创建依赖对象。
  8. Spring Boot的自动配置原理: Spring Boot的自动配置是通过@EnableAutoConfiguration注解来实现的。它利用SpringFactoriesLoader加载所有的自动配置类,这些自动配置类存放在META - INF/spring.factories文件中。自动配置类会根据当前应用的环境信息(如是否引入了某个依赖、配置文件中的属性等),通过条件判断来决定是否启用某个配置。例如,如果应用中引入了数据库相关的依赖,自动配置类会根据数据库的类型等信息,自动配置数据源、事务管理器等相关组件,极大地简化了开发过程。
  9. MyBatis的#{}和${}的区别:
    • #{}:会进行预编译,将参数的值作为一个占位符,在SQL语句中用?代替,这样可以防止SQL注入。例如,当传入一个参数name时,SQL语句会变为select * from user where name =?,然后通过PreparedStatement设置参数值,保证了安全性。
    • :不会进行预编译,它会直接将参数的值拼接到SQL语句中。例如,当传入参数tableName时,SQL语句会变为selectfrom{}:不会进行预编译,它会直接将参数的值拼接到SQL语句中。例如,当传入参数tableName时,SQL语句会变为select * from {tableName},如果参数值是用户可控的,就可能会导致SQL注入风险。