一、基础概念

1. JDK、JRE、JVM 的区别与联系?

  • JVM(Java虚拟机):运行Java字节码的虚拟计算机,是Java跨平台的核心。
  • JRE(Java运行环境):包含JVM和核心类库,用于运行Java程序,不包含开发工具。
  • JDK(Java开发工具包):包含JRE + 开发工具(如javac编译器、jar打包工具等)。
  • 联系JDK ⊇ JRE ⊇ JVM,开发时用JDK,运行时只需JRE。

2. Java是编译型还是解释型语言?

Java是编译与解释并存的语言:

  • 先由javac.java源文件编译为.class字节码文件(编译)。
  • 再由JVM对字节码进行解释执行或通过JIT即时编译器编译为本地机器码执行(解释+编译)。

3. 面向对象三大特性(封装、继承、多态)的理解?

  • 封装:将数据和操作封装在类中,隐藏内部实现细节,只暴露必要的接口。通过访问修饰符(private, protected, public)实现。
  • 继承:子类可继承父类的属性和方法,实现代码复用。Java是单继承,但可通过接口实现多继承效果。
  • 多态:同一行为的不同表现形式,分为编译时多态(方法重载)和运行时多态(方法重写)。运行时多态依赖继承、重写、父类引用指向子类对象。

4. 抽象类与接口的区别(JDK8+)?

对比项 抽象类 接口
实例化 不能 不能
构造方法
方法实现 可以有具体方法 JDK8起支持defaultstatic方法
成员变量 无限制 只能是public static final常量
继承关系 单继承 可多实现(多继承)
设计理念 is-a 关系,模板式设计 has-a / can-do 关系,行为契约

5. ==equals() 的区别?

  • ==:基础类型比较值,引用类型比较内存地址。
  • equals():Object类中默认用==比较地址,但String、Integer等重写了equals(),转而比较内容。
  • 重点:重写equals()必须重写hashCode(),否则在HashSet、HashMap中会出现逻辑错误。

6. final 关键字的作用?

  • 修饰类:类不能被继承(如String类)。
  • 修饰方法:方法不能被重写。
  • 修饰变量:变量成为常量,基础类型值不可变,引用类型地址不可变但内容可变。

7. String、StringBuilder、StringBuffer 的区别?

  • String:不可变类,每次修改都生成新对象,线程安全(因不可变)。
  • StringBuffer:可变类,线程安全(方法用synchronized修饰),效率较低。
  • StringBuilder:可变类,线程不安全,单线程下性能最优。

二、异常处理

8. Java 异常体系是怎样的?

Throwable
├── Error(严重问题,不建议处理,如OutOfMemoryError)
└── Exception
    ├── RuntimeException(运行时异常/非受检异常,如NullPointerException)
    └── 非RuntimeException(编译时异常/受检异常,如IOException)

9. finally 块一定会执行吗?final、finally、finalize 的区别?

  • finally:通常都会执行,除非在try/catch中调用了System.exit(0)或JVM崩溃。
  • final:关键字,修饰类、方法、变量。
  • finally:异常处理中保证代码执行的块。
  • finalize:Object类的方法,对象被GC回收前调用,JDK9已废弃,不推荐使用。

三、集合框架

10. ArrayList 和 LinkedList 的区别?

对比项 ArrayList LinkedList
底层结构 动态数组 双向链表
随机访问 快 O(1) 慢 O(n)
增删(非尾部) 慢(需移动元素) O(n) 快(只需修改指针) O(1)
内存占用 相对小(只存数据) 相对大(存数据+前后指针)
适用场景 频繁读取、尾部插入 频繁头尾插入删除

11. HashMap 的底层原理(JDK8)?

  • 数据结构:数组 + 链表 + 红黑树。
  • 存储过程
    1. 通过hashCode()计算哈希值,再通过(n-1) & hash确定桶下标。
    2. 该桶为空,直接存入。
    3. 不为空,判断key是否相等(equals),相等则覆盖。
    4. 不相等则以链表形式插入。
    5. 链表长度≥8且数组长度≥64时,链表转为红黑树,提升搜索效率。
  • 扩容机制:默认容量16,负载因子0.75,超过阈值时扩容为原来的2倍。
  • 为什么线程不安全:并发put可能导致数据丢失(覆盖)、链表成环(JDK7头插法)、size计数不准。

12. HashMap 与 Hashtable、ConcurrentHashMap 的区别?

对比项 HashMap Hashtable ConcurrentHashMap
线程安全 是(synchronized方法) 是(分段锁/CAS+synchronized)
效率 低(全表锁) 高(细粒度锁)
null键值 允许一个null键 不允许 不允许
JDK版本 1.2 1.0(已不推荐) 1.5

13. List、Set、Map 三者的区别?

  • List:有序(存入顺序),可重复,按索引访问。
  • Set:无序(部分如LinkedHashSet有序),不可重复,底层多为Map实现。
  • Map:键值对存储,key不可重复,value可重复。

四、多线程与并发

14. 创建线程有哪几种方式?

  1. 继承Thread类,重写run()方法。
  2. 实现Runnable接口,作为参数传入Thread
  3. 实现Callable接口 + FutureTask(有返回值,可抛异常)。
  4. 通过线程池(Executors框架)创建(推荐)。

15. synchronized 关键字的用法与锁升级?

  • 修饰对象
    • 修饰实例方法:锁是当前对象实例this
    • 修饰静态方法:锁是当前类的Class对象。
    • 修饰代码块:锁是括号里指定的对象。
  • 锁升级(JDK6后优化):偏向锁 → 轻量级锁(CAS自旋) → 重量级锁(操作系统互斥量),随竞争程度逐渐膨胀。

16. volatile 关键字的作用?

  • 保证可见性:一个线程修改了变量,其他线程立即可见(强制读写主内存,禁止线程工作内存缓存)。
  • 禁止指令重排序:通过内存屏障防止JVM对指令的乱序执行优化。
  • 不保证原子性:如i++这种复合操作不具备原子性。

17. wait()sleep() 的区别?

对比项 wait() sleep()
所属类 Object类 Thread类
锁释放 调用后释放锁 调用后不释放锁
唤醒条件 notify()/notifyAll()唤醒,或设置超时 时间到自动唤醒
使用位置 必须在synchronized块中 任意位置

18. 线程池的核心参数与拒绝策略?

  • 七大核心参数ThreadPoolExecutor):
    1. corePoolSize 核心线程数
    2. maximumPoolSize 最大线程数
    3. keepAliveTime 空闲存活时间
    4. unit 时间单位
    5. workQueue 工作队列(有界/无界)
    6. threadFactory 线程工厂
    7. handler 拒绝策略
  • 四种拒绝策略
    • AbortPolicy:抛异常(默认)
    • CallerRunsPolicy:由调用线程执行任务
    • DiscardOldestPolicy:丢弃队列最早任务
    • DiscardPolicy:静默丢弃新任务

五、JVM 基础

19. JVM 内存模型(运行时数据区)包含哪些部分?

  1. 程序计数器:线程私有,记录当前线程执行字节码的行号。
  2. 虚拟机栈:线程私有,由栈帧组成,每个方法执行时创建栈帧,存放局部变量表等。
  3. 本地方法栈:为Native方法服务。
  4. :所有线程共享,存放对象实例,GC的主要区域。
  5. 方法区(元空间):存储类信息、常量、静态变量、即时编译后的代码。JDK8后用本地内存的元空间替代永久代。

20. 常见垃圾回收算法?

  1. 标记-清除:标记存活对象,清除未标记对象。产生内存碎片。
  2. 标记-复制:将内存分为两块,存活对象复制到另一块,整体清除当前块。无碎片但浪费空间(新生代使用)。
  3. 标记-整理:标记后,存活对象向一端移动,清理边界外内存。无碎片,代价较高(老年代使用)。
  4. 分代收集:新生代用复制算法,老年代用标记-清除/整理算法。

六、进阶特性(JDK8+)

21. Lambda 表达式与函数式接口?

  • 函数式接口:只有一个抽象方法的接口,可用@FunctionalInterface注解标识。
  • Lambda表达式:用于简化匿名内部类的写法,本质是函数式接口的实现。

22. Stream 流的常用操作?

操作类型 常用API
中间操作(惰性求值) filtermapsorteddistinctlimit
终端操作(触发计算) collectforEachreducecountanyMatch

23. Optional 类的作用?

解决NullPointerException问题,作为可能为null的值的容器,强制要求使用者显式处理null情况。常用方法:ofNullable()orElse()ifPresent()


七、编码实践

24. ComparableComparator 的区别?

  • Comparable:内部比较器,类自身实现compareTo方法,定义自然排序规则。
  • Comparator:外部比较器,不修改类本身,可定义多个排序规则。使用时作为参数传入sort方法。

25. 深拷贝与浅拷贝的区别?

  • 浅拷贝:复制对象时,基础类型复制值,引用类型复制引用地址(指向同一对象)。
  • 深拷贝:复制对象时,引用类型也会创建新对象并复制内容,两者完全独立。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐