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

36 阅读7分钟

面试官:请简要介绍一下Java核心知识在实际业务场景中的应用。

王铁牛:嗯……Java核心知识嘛,像面向对象编程,能让代码结构清晰,可维护性强。比如开发一个电商系统,商品类、用户类等就可以通过面向对象来组织。

面试官:那JUC在高并发场景下是如何发挥作用的?

王铁牛:JUC提供了很多并发工具类,像CountDownLatch可以用于线程同步,比如多个线程等待某个条件达成后再一起执行。

面试官:JVM的内存模型你了解多少?

王铁牛:这个……大概就是有堆、栈、方法区这些吧,对象在堆里创建,方法执行时相关数据在栈里。

第一轮结束。

面试官:多线程中如何保证线程安全?

王铁牛:可以用synchronized关键字,或者用Lock接口。

面试官:线程池的参数都有什么作用?

王铁牛:核心线程数就是基本的线程数量,最大线程数是能容纳的最大线程,队列用来存放任务。

面试官:HashMap在多线程环境下会出现什么问题?

王铁牛:可能会出现链表成环,导致死循环。

第二轮结束。

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

王铁牛:依赖注入、面向切面编程这些吧。

面试官:Spring Boot如何快速搭建一个Web应用?

王铁牛:就是用一些starter依赖,简单配置下就能跑起来。

面试官:MyBatis的动态SQL有什么作用?

王铁牛:能根据不同条件动态生成SQL语句,比如根据用户输入条件查询数据。

第三轮结束。

面试结束,面试官表示会让王铁牛回家等通知。虽然王铁牛在一些简单问题上回答得还可以,但复杂问题的回答显得很不清晰,整体表现还有待提高。

答案:

  1. Java核心知识
    • 面向对象编程在实际业务场景中,能将业务逻辑模块化。比如电商系统中,商品类可以包含商品的属性(名称、价格、库存等)和方法(计算总价、判断库存是否充足等)。通过封装、继承和多态,提高代码的可维护性和扩展性。不同类型的商品可以继承商品类,实现各自的特殊行为。
  2. JUC
    • CountDownLatch:它是一个同步辅助类,允许一个或多个线程等待其他线程完成操作。例如,在一个多线程任务中,主线程需要等待多个子线程都完成数据处理后再进行汇总操作。可以创建一个CountDownLatch对象,构造函数传入子线程的数量。每个子线程完成任务后调用countDown()方法,主线程调用await()方法等待,直到计数器变为0,主线程继续执行。
  3. JVM内存模型
    • 堆:是Java虚拟机所管理的内存中最大的一块,被所有线程共享。对象实例以及数组都在堆上分配内存。堆可以细分为新生代、老年代和永久代(Java 8之后是元空间)。新生代用于存放新创建的对象,老年代存放经过多次垃圾回收后仍然存活的对象。永久代(元空间)用于存放类信息、常量、静态变量等。
    • 栈:每个线程都有自己独立的栈空间。栈中主要存放局部变量、方法调用的上下文等。当一个方法被调用时,会在栈中创建一个栈帧,用于存储该方法的局部变量和操作数。方法执行结束后,栈帧被销毁。
    • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  4. 多线程保证线程安全
    • synchronized关键字:它可以修饰方法或者代码块。当一个线程访问被synchronized修饰的方法或代码块时,会首先获取对象的锁。如果锁被其他线程持有,该线程会进入等待状态,直到锁被释放。例如,在一个银行账户类中,对存款和取款方法使用synchronized修饰,可以保证在多线程环境下账户余额的正确性。
    • Lock接口:相比于synchronized,Lock接口提供了更灵活的锁控制。比如可以实现公平锁,让等待时间最长的线程优先获取锁。通过Lock接口的lock()方法获取锁,unlock()方法释放锁。并且可以通过tryLock()方法尝试获取锁,避免死锁。
  5. 线程池参数
    • 核心线程数:线程池创建时初始化的线程数量。当提交的任务数小于核心线程数时,线程池会创建新线程来执行任务。
    • 最大线程数:线程池能够容纳的最大线程数量。当提交的任务数大于核心线程数且任务队列已满时,会创建新线程,直到线程数达到最大线程数。
    • 队列:用于存放提交的任务。当任务数大于核心线程数时,新提交的任务会被放入队列中。常用的队列有ArrayBlockingQueue、LinkedBlockingQueue等。
  6. HashMap在多线程环境下的问题
    • 在多线程环境下,HashMap可能会出现链表成环问题,进而导致死循环。这是因为在扩容时,如果多个线程同时进行插入操作,可能会导致链表结构发生变化,形成环形链表。例如,当一个线程在扩容过程中重新计算节点位置时,另一个线程可能正在修改链表结构,导致新的节点插入位置错误,最终形成环形链表。当后续有线程访问该HashMap时,可能会陷入死循环。
  7. Spring框架核心特性
    • 依赖注入:通过控制反转(IoC)的方式,将对象的依赖关系由程序主动创建改为由容器注入。例如,一个业务类需要调用另一个数据访问类,传统方式是在业务类中直接创建数据访问类的实例,而在Spring中,可以通过配置让容器将数据访问类的实例注入到业务类中。
    • 面向切面编程(AOP):允许将一些横切关注点(如日志记录、事务管理等)与业务逻辑分离。通过定义切面和切点,在不修改业务代码的情况下,为业务方法添加额外的功能。比如在方法执行前后记录日志,或者在方法出现异常时进行事务回滚。
  8. Spring Boot快速搭建Web应用
    • Spring Boot通过引入starter依赖来简化项目搭建。例如,引入spring-boot-starter-web依赖,它会自动配置好Web应用所需的基本组件,如Tomcat服务器、Spring MVC等。开发者只需要在配置文件中进行一些简单的配置,如指定端口号、配置数据源等,就可以快速启动一个Web应用。可以通过创建Controller类,使用@RequestMapping注解来定义接口,处理HTTP请求。
  9. MyBatis动态SQL
    • 动态SQL允许根据不同的条件动态生成SQL语句。例如,在一个用户查询功能中,可能根据用户输入的姓名、年龄、性别等条件进行查询。使用MyBatis的动态SQL,可以通过标签来判断条件是否存在,然后动态拼接SQL语句。如:
    <select id="selectUsers" resultType="User">
        SELECT * FROM users
        <where>
            <if test="name!= null">
                AND name = #{name}
            </if>
            <if test="age!= null">
                AND age = #{age}
            </if>
            <if test="gender!= null">
                AND gender = #{gender}
            </if>
        </where>
    </select>
    
    这样,当调用该查询方法时,如果传入了相应的参数,就会在SQL语句中添加对应的条件。