news 2026/7/16 3:59:16

Java基础面试知识点02

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java基础面试知识点02

1. hashCode和equals

hashCode介绍

hashCode()的作用是获取哈希码,也称为散列码,它实际上是返回一个int整数,这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Object.java中,Java中的任何类都包含了hashCode()函数。

散列表存储的是键值对(key-value),特点是:能根据key快速检索出对应的value,这其中就利用到了散列码(可以快速找到需要的对象)。

为什么要有hashCode,以“HashSet 如何检查重复”为例:

对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,看该位置是否有值,如果没有,HashSet 会假设对象没有重复出现。但是如果发现该索引位置已有元素,这时会调用 equals() 方法来检查两个对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会发生哈希冲突,将新对象挂载到链表或红黑树上。这样就大大减少了 equals 的调用次数,相应就大大提高了执行速度。

  • 如果两个对象相等,则hashCode一定相同
  • 两个对象相等,对这两个对象分别调用equals方法都返回true
  • 两个对象有相同的hashCode值,他们也不一定是相等的
  • 因此,equals方法被重写过,则hashCode方法也必须被重写
  • hashCode()的默认行为是对堆上的对象生成哈希值。如果没有重写hashCode(),即便两个对象成员变量完全一致,该类的两个对象哈希码大概率不同,equals默认比较地址也不会判定相等

2. ConcurrentHashMap原理,jdk7和jdk8版本的区别

JDK7

底层数据结构

ReentrantLock + Segment + HashEntry
外层是Segment数组,单个Segment内部封装HashEntry数组,数组每个下标位置挂载单向HashEntry链表。

寻址查询

采用两次哈希定位:

  1. 第一次哈希锁定目标Segment;
  2. 第二次哈希在该Segment内定位链表头节点。

加锁机制

Segment直接继承ReentrantLock实现分段锁;
仅锁定当前操作的Segment分段,其余Segment完全不受锁影响;
并发上限等于Segment分段数量,可在构造方法手动指定;
单个Segment内部数组扩容,不会干扰其他分段。

get读操作

查询全程不需要加锁,依靠volatile修饰变量保证数据可见性。

JDK8

底层数据结构

synchronized + CAS + Node + 链表+红黑树
废弃Segment分层结构,底层直接是Node数组;
链表长度超过阈值会转为红黑树优化查询效率;
Node节点里val值与next指针均用volatile修饰,保障多线程可见。

基础修改操作

查找、替换、新增赋值优先使用CAS无锁操作。

锁策略

不再锁整个分段,仅对当前哈希桶链表头head节点加synchronized锁;
锁粒度大幅缩小,不会阻塞其他桶位元素读写,并发性能更高;
扩容支持多线程并发协助迁移数据,不会阻塞全局读写。

读操作无锁设计

Node的val、next被volatile修饰,读写之间数据互相可见;
哈希数组table本身由volatile修饰,扩容时读线程可以及时感知数组变化。

对比总结

  • JDK7依靠Segment分段锁+ReentrantLock,锁定整个分段,两次hash寻址,各分段独立扩容;
  • JDK8移除Segment,改用CAS+对桶头加synchronized锁,链表过长转为红黑树,支持多线程并发扩容,锁粒度更细、并发能力更强;
  • 两个版本get操作均不加锁,依靠volatile关键字保证读取数据可见性。

3. 如何实现一个IOC容器

简要回答

  1. 配置文件配置包扫描路径
  2. 递归包扫描获取.class文件
  3. 利用反射机制,筛选需要交给IOC容器管理的类
  4. 对需要注入依赖的属性完成依赖注入

详细回答

  1. 在配置文件中指定需要扫描的包路径
  2. 自定义注解,分别标记控制层、业务层、持久层、依赖注入、读取配置等标识注解
  3. 读取配置文件中的扫描包路径,遍历路径下文件与文件夹,将所有后缀为.class的文件存入Set集合去重存储
  4. 遍历Set集合,通过反射获取类对象,筛选带有指定组件注解的类,使用线程安全Map存储实例对象,完成Bean注册
  5. 遍历IOC容器中所有Bean实例,遍历成员属性,识别注入注解,递归获取对应Bean完成属性依赖注入

4. 什么是字节码?采用字节码的好处是什么?

Java中引入了虚拟机的概念,这台虚拟机在任意平台都为编译程序提供统一接口。
编译程序只需要面向虚拟机,生成虚拟机能够识别的代码,再由JVM解释器将虚拟机代码转换为当前操作系统的机器码执行。在Java中,这种专供JVM解析执行的中间代码叫做字节码(即扩展名为.class的文件),它不面向任何特定CPU处理器,只面向Java虚拟机。

执行流程:.java源代码 → javac编译 →.class字节码文件 → JVM解析翻译为机器码 → CPU执行

好处

  1. 实现跨平台:源码仅需编译一次生成字节码,不同操作系统只要安装对应平台版本JVM即可运行该字节码文件,实现一次编译,到处运行。
  2. 兼顾运行效率与跨平台可移植性,弥补传统纯解释型语言逐行解释执行速度慢的缺陷。

5. Java类加载器

Java源码编译后生成class字节码文件存储在磁盘,类加载器ClassLoader是JVM中专负责查找、读取class字节码文件,将类加载至JVM方法区,并在堆中生成对应Class对象,程序后续依靠该Class对象创建实例、访问类成员。

JVM内置三种类加载器,自上而下双亲委派层级关系如下:

  1. 启动类加载器(Bootstrap ClassLoader)
    最顶层加载器,由C++编写,本身并非Java类;负责加载JDK核心基础类库,例如java.lang包下Object、String等核心类,加载路径为jre/lib下核心rt.jar等包。

  2. 扩展类加载器(Extension ClassLoader)
    父加载器为启动类加载器,用于加载jre/lib/ext扩展目录下的jar包,用来拓展JDK原生基础功能。

  3. 应用程序/系统类加载器(Application ClassLoader)
    开发默认使用的加载器,父加载器是扩展类加载器;加载项目classpath下自定义编写代码,以及Maven/Gradle引入的第三方依赖Jar包。

6. 双亲委派模型

加载流程

  1. 应用类加载器收到类加载请求,不会自身直接加载,优先委托父加载器(扩展类加载器)尝试加载;
  2. 扩展类加载器继续向上委托给顶层启动类加载器;
  3. 启动类加载器在自身加载路径范围内查找目标类,查找成功则直接加载;若查找失败,请求逐层向下回退,由下级加载器在自身路径中完成类加载。

作用

  1. 安全防护:防止开发者自定义java.lang.String这类核心类覆盖JDK原生基础类,避免恶意代码篡改底层API,保障程序运行安全。
  2. 避免重复加载:同一个类只会被某一个加载器加载一次,防止JVM方法区中存在多份完全相同的Class对象,节约内存空间。

7. Java中的异常体系

Java中所有异常与错误的顶层父类为Throwable
Throwable下分为两大子类:ExceptionError

  • Error:属于程序无法手动处理的严重系统级错误,一旦触发通常直接终止程序进程。
  • Exception:不会直接导致程序整体崩溃,又划分为运行时异常RuntimeException与受检异常CheckedException
    • RuntimeException运行时异常:程序运行期间抛出,编译阶段不会强制校验捕获,会终止当前线程执行。
    • CheckedException受检异常:编译期强制校验,必须使用try-catch捕获或者throws向上抛出,否则代码编译报错。

8. GC如何判断对象可以被回收

1. 引用计数法

给每个对象维护一个引用计数器,新增引用计数+1,引用失效释放计数-1,计数器为0时标记可回收。
缺陷:若A对象持有B引用、B同时持有A引用,二者外部无其他引用,计数器仍为1,对象永远无法被GC回收,出现内存泄漏,因此Java未采用该算法。

2. 可达性分析法(Java正式采用)

以GC Roots作为起始节点向下遍历搜索,遍历经过的链路称为引用链。若一个对象没有任何引用链与GC Roots相连,则判定该对象不可达,标记为可回收对象。

可作为GC Roots的对象:

  1. 虚拟机栈(栈帧本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中Native方法JNI引用的对象

对象回收补充说明

被标记为不可达不等于立即销毁:对象拥有一次自救机会,依靠finalize()方法。

  1. 对象第一次被标记不可达时,放入F-Queue队列;
  2. 由低优先级Finalizer守护线程执行对象finalize()方法;
  3. 若在finalize方法内重新将该对象赋值给GC Roots可达引用,对象自救成功,跳过本次GC回收;
  4. 若自救失败,第二次标记后该对象会被直接回收。

9. 线程的生命周期/线程有哪些状态

线程共五种核心状态:新建、就绪、运行、阻塞、终止。
阻塞状态细分三类:

阻塞分类

  1. 等待阻塞:运行线程执行wait()方法,释放持有的所有锁资源,线程移入等待池。无法自动唤醒,必须由其他线程调用notify()或notifyAll()唤醒;wait()是Object类方法。
  2. 同步阻塞:线程尝试获取synchronized同步锁时,锁已被其他线程占用,线程进入锁池阻塞排队竞争锁。
  3. 其他阻塞:线程执行sleep()、join()方法,或是发起IO请求时进入阻塞。sleep超时、join等待线程结束、IO操作完成后,线程重新转为就绪状态;sleep()是Thread类静态方法。

各状态详解

  1. 新建状态(New):仅new创建Thread线程对象,未调用start(),未开启线程调度。
  2. 就绪状态(Runnable):调用start()后线程进入就绪线程池,具备运行资格,等待操作系统分配CPU时间片。
  3. 运行状态(Running):就绪线程获取CPU时间片,执行run()方法内业务代码。
  4. 阻塞状态(Blocked):线程主动/被动放弃CPU使用权,暂停执行,解除阻塞后只能先回到就绪队列。
  5. 终止状态(Dead):run()方法正常执行完毕,或运行过程抛出未捕获异常终止线程,线程生命周期结束。

10. sleep()、wait()、join()、yield()的区别

锁池与等待池概念

  • 锁池:所有竞争同一把synchronized同步锁的线程存入锁池;锁被占用时其余线程在锁池等待;锁释放后锁池内线程争抢锁,抢到锁后进入就绪队列等待CPU调度。
  • 等待池:调用wait()后线程进入等待池,等待池内线程不会参与锁竞争;必须被notify/notifyAll唤醒后,线程才会转入锁池参与锁争夺。notify随机选取一条等待池线程移入锁池;notifyAll将等待池全部线程移入锁池。

方法区别

  1. 归属类:sleep是Thread类静态本地方法;wait是Object类本地方法。
  2. 锁释放:sleep不会释放持有的同步锁;wait会释放当前对象锁并进入等待队列。
  3. 同步依赖:sleep无需配合synchronized同步代码块;wait必须写在synchronized修饰的代码内。
  4. 唤醒机制:sleep休眠时间结束自动解除阻塞;无参wait()必须被其他线程唤醒,带超时时间wait()超时后自动唤醒。
  5. 使用场景:sleep多用于线程定时休眠、轮询间隔暂停;wait用于多线程之间生产者消费者等线程间通信场景。
  6. CPU调度:sleep让出CPU时间片强制上下文切换;wait被唤醒后需要重新竞争锁,不一定立刻获取CPU执行权。

yield()

执行yield()后线程直接回到就绪状态,主动让出本次CPU执行权,但依旧保留CPU调度资格,操作系统下一次调度仍有可能再次选中该线程执行。

join()

在主线程B中调用线程A.join(),线程B进入阻塞状态,直到线程A执行完毕结束,或是调用interrupt中断等待,B才会解除阻塞继续执行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 3:56:09

c++基础入门day3 - 运算符

c基础入门day3 工具:vs2026 课程:【黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难】 3 运算符 3.1 算数运算符 作用:用于处理四则运算+ - * /%取余(取模)前置递增/递减:先增/减1&…

作者头像 李华
网站建设 2026/7/16 3:55:22

y1,y2王晨旭总复习笔记1 2026.7.14

一,单位元与逆元(1)单位元:不影响运算的元素,如加法单位元:0乘法:1逻辑与:1逻辑或:0矩阵乘法:单位矩阵(主对角线(左上到右下&#xff…

作者头像 李华
网站建设 2026/7/16 3:51:53

从算法优化到芯片原生加速:星凡智能如何提升物理AI计算效率

AI正在进入真实世界,但落地并不容易。算力贵、显存高、功耗大、硬件成本居高不下。面对这些问题,星凡智能没有将技术路线局限于通用算力扩展,而是围绕具身智能体任务特点,推进算法、推理引擎、芯片架构与系统产品协同优化&#xf…

作者头像 李华
网站建设 2026/7/16 3:50:17

电子招投标实务指南:系统架构、操作流程与关键注意事项

一、电子招投标的定义与发展趋势电子招标投标活动,是指以数据电文形式,依托电子招标投标系统完成的全部或者部分招标投标交易、公共服务和行政监督活动。理解电子招投标需要把握几个关键点。首先,它依据现行招标投标法律法规开展,…

作者头像 李华
网站建设 2026/7/16 3:49:10

Ubuntu 14.04一键安装Oracle 11gR2单机实战指南

1. 项目概述:为什么在 Ubuntu 14.04 上“一键安装 Oracle 11gR2 单机”这件事,至今还有人反复搜索? 你点开这个标题,大概率不是为了怀旧——没人会主动选一个早已结束官方支持(2019年4月EOL)、内核版本停留…

作者头像 李华
网站建设 2026/7/16 3:46:24

透明化数字孪生导航定位遥感时敏巡检技术

随着空地一体化智能巡检体系快速发展,传统人工巡检、单源遥感监测、离线定位核查模式,存在场景还原度低、空间定位偏差大、数据更新滞后、隐患发现不及时、无法动态溯源等突出问题,难以满足基础设施、河道路网、电力廊道、山地边境、大型园区…

作者头像 李华