《互联网大厂面试:Java核心知识、框架与中间件大考验》

36 阅读10分钟

互联网大厂面试:Java核心知识、框架与中间件大考验

王铁牛怀揣着忐忑又期待的心情,坐在了互联网大厂的面试会议室里,对面坐着表情严肃的面试官,一场决定他职业走向的面试即将开始。

第一轮面试开始 面试官:我们先从Java核心知识问起,能说一下Java中多态的实现方式有哪些吗? 王铁牛:多态的实现方式主要有两种,一种是方法重载,就是在一个类中可以有多个同名方法,但参数列表不同;另一种是方法重写,子类重写父类的方法。 面试官:不错,回答得很准确。那你说说Java的访问修饰符有哪些,它们的作用范围是怎样的? 王铁牛:Java有四种访问修饰符,分别是private、default(默认,不写修饰符时)、protected和public。private只能在本类中访问;default可以在本包内访问;protected除了本包内访问,还可以在不同包的子类中访问;public可以在任何地方访问。 面试官:非常好。那在多线程场景下,如何保证数据的线程安全呢? 王铁牛:可以使用synchronized关键字来对代码块或者方法进行同步,也可以使用Lock接口的实现类,像ReentrantLock。

第二轮面试开始 面试官:接下来聊聊JUC相关的。说说CountDownLatch和CyclicBarrier的区别是什么? 王铁牛:嗯……这个嘛,好像都是跟线程同步有关的,具体区别我有点不太确定了。 面试官:那我们换个问题,说说线程池的核心参数有哪些,它们分别有什么作用? 王铁牛:线程池的核心参数有corePoolSize、maximumPoolSize、keepAliveTime、TimeUnit和workQueue。corePoolSize是核心线程数,maximumPoolSize是最大线程数,但是它们具体怎么工作的我有点说不太清楚。 面试官:再问一个,JVM的内存模型是怎样的,各个区域的作用是什么? 王铁牛:JVM内存模型有堆、栈、方法区这些,堆是存放对象的,栈是存放局部变量的,方法区存放类的信息这些,但具体细节我也不太能说完整。

第三轮面试开始 面试官:我们来谈谈框架相关的。Spring的AOP和IOC是什么,它们的作用是什么? 王铁牛:AOP好像是面向切面编程,能实现一些日志记录、事务管理这些功能;IOC是控制反转,把对象的创建和依赖关系的管理交给Spring容器,具体怎么实现我不太明白。 面试官:那Spring Boot和Spring有什么区别和联系呢? 王铁牛:Spring Boot是在Spring基础上的简化开发框架,好像能自动配置一些东西,但具体的区别我说不出来。 面试官:最后问一下,MyBatis的工作原理是什么? 王铁牛:MyBatis是一个持久层框架,能和数据库交互,但它具体怎么工作的我不太清楚。

面试官:好了,今天的面试就到这里,你回家等通知吧。我们会综合评估后尽快给你回复。

问题答案

  1. Java中多态的实现方式有哪些
    • 方法重载:在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。参数列表不同包括参数的个数不同、参数的类型不同或者参数的顺序不同。方法重载与返回值类型无关,它主要是为了方便开发者使用,让代码更简洁易读。例如,在一个类中可以有多个不同参数的构造方法。
    • 方法重写:子类对父类中允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。即外壳不变,核心重写。重写的好处在于子类可以根据需要,定义特定于自己的行为。比如,父类有一个动物叫的方法,子类猫可以重写这个方法,实现猫叫的特定行为。
  2. Java的访问修饰符有哪些,它们的作用范围是怎样的
    • private:被private修饰的成员,只能在定义它们的类中被访问,其他类无法直接访问。这是一种最严格的访问控制,用于隐藏类的内部实现细节,提高类的封装性。例如,类中的私有属性和私有方法,外部类不能直接调用。
    • default(默认):如果没有指定访问修饰符,就是默认访问权限。默认访问权限的成员可以被同一个包中的其他类访问,但不同包中的类无法访问。它提供了一种包级别的访问控制。
    • protected:protected修饰的成员,在同一个包内可以像默认访问权限一样被访问,同时,在不同包的子类中也可以访问。它主要用于在继承关系中,让子类能够访问父类的一些成员,同时对其他无关类进行一定的访问限制。
    • public:被public修饰的成员可以被任何类访问,无论这些类是否在同一个包中。它是最宽松的访问控制,通常用于定义类的公共接口,让其他类可以自由使用。
  3. 在多线程场景下,如何保证数据的线程安全
    • synchronized关键字:可以修饰方法或者代码块。当修饰方法时,该方法在同一时间只能被一个线程访问,其他线程需要等待。当修饰代码块时,需要指定一个对象作为锁,同一时间只有获得该锁的线程才能执行代码块中的内容。例如:
public class SynchronizedExample {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public void incrementBlock() {
        synchronized (this) {
            count++;
        }
    }
}
- **Lock接口及其实现类(如ReentrantLock)**:Lock是一个接口,ReentrantLock是其实现类。使用Lock可以更灵活地控制锁的获取和释放。例如:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}
  1. CountDownLatch和CyclicBarrier的区别是什么
    • CountDownLatch:它是一个同步辅助类,允许一个或多个线程等待其他线程完成操作。它通过一个计数器来实现,计数器的初始值为线程的数量。当一个线程完成自己的任务后,计数器的值就会减1。当计数器的值为0时,表示所有线程都已经完成任务,等待的线程可以继续执行。例如,主线程等待多个子线程完成数据加载后再进行后续操作。
    • CyclicBarrier:它也是一个同步辅助类,允许一组线程相互等待,直到所有线程都到达一个公共屏障点。它的计数器可以循环使用,当所有线程都到达屏障点后,计数器会重置,可以再次使用。例如,多个运动员在起跑线等待,当所有运动员都准备好后,一起起跑。
  2. 线程池的核心参数有哪些,它们分别有什么作用
    • corePoolSize:核心线程数,线程池在初始化时会创建的线程数量。当提交的任务数小于核心线程数时,线程池会创建新的线程来执行任务。
    • maximumPoolSize:最大线程数,线程池允许创建的最大线程数量。当任务数超过核心线程数,并且任务队列已满时,线程池会创建新的线程,直到达到最大线程数。
    • keepAliveTime:线程空闲时间,当线程池中的线程数量超过核心线程数时,多余的空闲线程在等待新任务的最长时间。如果超过这个时间还没有新任务,这些线程会被销毁。
    • TimeUnit:keepAliveTime的时间单位,如秒、毫秒等。
    • workQueue:任务队列,用于存放提交但尚未被执行的任务。常见的任务队列有ArrayBlockingQueue、LinkedBlockingQueue等。
  3. JVM的内存模型是怎样的,各个区域的作用是什么
    • 堆(Heap):是JVM中最大的一块内存区域,用于存放对象实例和数组。所有通过new关键字创建的对象都存放在堆中。堆是线程共享的,会被垃圾回收机制管理。
    • 栈(Stack):主要用于存储局部变量和方法调用的上下文。每个线程都有自己独立的栈,栈中的数据是线程私有的。当方法被调用时,会在栈中创建一个栈帧,用于存储方法的局部变量、参数和返回值等信息。方法执行完毕后,栈帧会被弹出。
    • 方法区(Method Area):用于存储类的信息、常量、静态变量等。方法区也是线程共享的。在JDK 8之前,方法区也被称为永久代,JDK 8及以后使用元空间(Metaspace)来替代永久代。
    • 程序计数器(Program Counter Register):是一块较小的内存区域,它可以看作是当前线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器,它是线程私有的。
    • 本地方法栈(Native Method Stack):与栈类似,不过它是为本地方法服务的。本地方法是使用非Java语言(如C、C++)实现的方法。
  4. Spring的AOP和IOC是什么,它们的作用是什么
    • AOP(面向切面编程):是一种编程范式,它允许开发者在不修改原有业务逻辑的基础上,对程序进行增强。AOP通过将那些与业务无关,但却被多个业务模块所共同调用的逻辑(如日志记录、事务管理、权限验证等)封装起来,形成一个独立的模块,这个模块被称为切面。AOP的主要作用是提高代码的可维护性和可复用性,减少代码的重复。
    • IOC(控制反转):也称为依赖注入(Dependency Injection),是一种设计原则,它将对象的创建和依赖关系的管理从代码中分离出来,交给Spring容器来完成。在传统的编程中,对象的创建和依赖关系的管理是由代码直接控制的,而在IOC中,对象的创建和依赖关系的注入是由Spring容器自动完成的。这样可以降低代码的耦合度,提高代码的可测试性和可维护性。
  5. Spring Boot和Spring有什么区别和联系
    • 联系:Spring Boot是基于Spring框架构建的,它继承了Spring的核心特性,如IOC和AOP。Spring Boot可以使用Spring的所有功能,并且在Spring的基础上进行了简化和增强。
    • 区别:Spring是一个庞大的框架,需要开发者手动配置很多东西,如数据库连接、事务管理等。而Spring Boot则是一个快速开发框架,它通过自动配置的方式,减少了开发者的配置工作。Spring Boot提供了很多starter依赖,只需要添加相应的依赖,就可以快速集成各种功能,如Web开发、数据库访问等。同时,Spring Boot内置了嵌入式服务器,如Tomcat、Jetty等,方便开发者快速部署应用。
  6. MyBatis的工作原理是什么
    • 加载配置文件:MyBatis首先会加载配置文件,包括数据库连接信息、映射文件等。配置文件可以是XML文件或者Java代码。
    • 创建SqlSessionFactory:根据配置文件创建SqlSessionFactory,它是MyBatis的核心工厂类,用于创建SqlSession对象。
    • 创建SqlSession:通过SqlSessionFactory创建SqlSession对象,它是MyBatis与数据库交互的核心接口。SqlSession提供了执行SQL语句的方法,如select、insert、update、delete等。
    • 执行SQL语句:通过SqlSession对象执行SQL语句。MyBatis会根据映射文件中的配置,将SQL语句与Java对象进行映射,将查询结果封装成Java对象返回。
    • 关闭SqlSession:使用完SqlSession后,需要关闭它,释放资源。