一、基础语法
1. Java的三大特性是什么?分别简单解释其含义
核心结论 :Java三大特性为封装、继承、多态,是面向对象编程的核心基础。
- 封装 :将对象的属性和行为包装为类,隐藏内部实现细节,仅对外暴露公共访问接口,保证数据安全、降低耦合。
- 继承 :子类复用父类的属性和方法,并可扩展自身功能,减少代码冗余,体现类的层级关系。
- 多态:同一行为在不同子类中表现出不同形态,基于继承/接口实现,提升代码扩展性和灵活性。
2. Java中基本数据类型有哪些?对应的包装类分别是什么
Java有8种基本数据类型,均有对应包装类(包装类是引用类型,提供方法和泛型支持):
| 基本数据类型 | 包装类 | 取值范围 |
|---|---|---|
| byte | Byte | -128 ~ 127 |
| short | Short | -32768 ~ 32767 |
| int | Integer | -231 ~ 231-1 |
| long | Long | -263 ~ 263-1 |
| float | Float | 单精度浮点 |
| double | Double | 双精度浮点 |
| char | Character | 0 ~ 65535(Unicode) |
| boolean | Boolean | true/false |
3. int和Integer的区别是什么?自动装箱和自动拆箱的原理
核心区别
- 类型 :int是基本数据类型 ,Integer是int的包装类(引用类型);
- 存储 :int直接存数值 ,Integer存对象引用,需分配堆内存;
- 默认值 :int默认0 ,Integer默认null;
- 使用场景 :int用于普通数值计算,Integer用于泛型、集合、反射等场景。
自动装箱/拆箱原理
- 自动装箱 :基本类型→包装类(如
Integer a = 10),底层调用Integer.valueOf(10); - 自动拆箱 :包装类→基本类型(如
int b = a),底层调用a.intValue(); - 目的:简化基本类型与包装类的转换,无需手动调用方法。
4. String、StringBuffer、StringBuilder的区别?适用场景
| 特性 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 底层实现 | final修饰的char数组 | char数组 | char数组 |
| 可变性 | 不可变(修改即创建新对象) | 可变 | 可变 |
| 线程安全 | 安全(不可变) | 安全(synchronized) | 不安全 |
| 性能 | 低(频繁修改耗内存) | 中 | 高 |
适用场景
- String:字符串不修改、少量修改(如常量、配置);
- StringBuffer:多线程环境下频繁修改字符串;
- StringBuilder:单线程环境下频繁修改字符串(优先使用)。
5. Java中==和equals()的区别?重写equals()时为什么要重写hashCode()
==和equals()区别
- == :
- 基本类型:比较数值是否相等;
- 引用类型:比较内存地址是否相同(是否为同一对象)。
- equals() :
- 未重写:和==一样,比较内存地址;
- 重写(如String、Integer):比较对象内容是否相等。
重写equals必须重写hashCode的原因
- 规范:两个对象equals相等,hashCode必须相等;
- 场景:HashMap/HashSet通过hashCode定位存储位置,若只重写equals不重写hashCode,会导致相同内容的对象被存为多个,破坏集合唯一性。
6. final关键字可以修饰哪些内容?分别有什么作用
final表示不可改变 ,可修饰类、方法、变量:
- 修饰类 :类不能被继承(如String、Integer),无子类;
- 修饰方法 :方法不能被重写,保证方法逻辑不被修改;
- 修饰变量 :
- 基本变量:数值初始化后不可修改;
- 引用变量:引用地址不可变,对象内部属性可修改。
7. static关键字的作用?static方法和非static方法的区别
static核心作用
表示静态 ,属于类本身,不属于单个对象,随类加载而加载。
- 修饰变量:静态变量,所有对象共享一份内存;
- 修饰方法:静态方法,无需创建对象可直接调用;
- 修饰代码块:静态代码块,类加载时执行一次,用于初始化静态资源。
static方法 / 非static方法
| 特性 | 静态方法 | 非静态方法 |
|---|---|---|
| 归属 | 类 | 对象 |
| 调用方式 | 类名.方法名 | 对象.方法名 |
| 访问权限 | 只能访问静态成员 | 可访问静态+非静态成员 |
| this/super | 不能使用 | 可以使用 |
8. Java中的注释有哪几种?分别是什么
- 单行注释 :
// 注释内容,用于简短说明; - 多行注释 :
/* 注释内容 */,用于多行说明; - 文档注释 :
/** 注释内容 */,可生成API文档,包含参数、返回值说明。
9. break、continue、return的区别
- break :跳出当前循环/switch,终止整个循环结构;
- continue :跳过本次循环剩余代码,直接进入下一次循环;
- return :结束当前方法,返回结果(无返回值则直接退出方法)。
10. if-else和switch-case的区别?switch-case支持哪些数据类型
核心区别
- if-else:可判断区间、逻辑表达式 (如
a>10 && a<20),适用所有判断场景; - switch-case:仅判断固定值,结构清晰,效率略高。
switch支持类型
- 基本类型:byte、short、char、int;
- 包装类:Byte、Short、Character、Integer;
- 枚举:Enum;
- JDK7+:String;
- 不支持long、float、double、boolean。
11. 数组和集合的区别?数组的长度是固定的吗
核心区别
| 特性 | 数组 | 集合 |
|---|---|---|
| 长度 | 固定,创建后不可改 | 可变,动态扩容 |
| 存储类型 | 基本类型+引用类型 | 仅引用类型(泛型) |
| 功能 | 简单存储、遍历 | 提供增删改查、排序等方法 |
| 泛型支持 | 无 | 有,类型安全 |
数组长度
数组长度固定,创建时指定长度,无法直接扩容,需新建数组复制元素。
12. Java中异常的分类?Error和Exception的区别
异常分类
Throwable是顶级父类,分为Error 和Exception:
- Error :JVM级错误(如OOM、StackOverflowError),无法通过代码处理,只能避免;
- Exception :程序级异常,可通过try-catch处理,分为:
- 编译时异常(受检):IOException、SQLException,编译期必须处理;
- 运行时异常(非受检):NullPointerException、IndexOutOfBoundsException,运行时触发。
Error / Exception
- Error :JVM无法恢复的严重错误,无需捕获;
- Exception :程序逻辑问题,可捕获处理,保证程序正常运行。
13. try-catch-finally的执行顺序?finally块一定会执行吗
执行顺序
- 先执行try块,无异常直接执行finally;
- 有异常:执行catch块,再执行finally;
- finally最后执行,用于释放资源(如流、连接)。
finally不一定执行的场景
- JVM提前终止(如
System.exit(0)); - 线程被中断/杀死;
- try块中无限循环,未执行到finally。
二、面向对象
1. 什么是面向对象?面向对象和面向过程的区别
- 面向对象(OOP) :以对象为核心,将数据和行为封装为类,通过对象交互实现功能。
- 面向过程(POP) :以过程/步骤为核心,按步骤编写函数,一步步执行。
核心区别
| 特性 | 面向过程 | 面向对象 |
|---|---|---|
| 核心 | 步骤/函数 | 对象/类 |
| 耦合度 | 高 | 低 |
| 扩展性 | 差 | 好 |
| 适用场景 | 简单、固定逻辑 | 复杂、多变业务 |
2. 封装的意义是什么?如何实现封装
封装意义
- 隐藏实现细节,外部无法直接访问内部数据;
- 保证数据安全,通过公共方法控制数据访问;
- 降低耦合,内部修改不影响外部调用。
实现方式
- 用private修饰类的属性;
- 提供public的get/set方法,对外暴露属性访问入口;
- 在get/set中添加数据校验逻辑。
3. 继承的好处是什么?Java支持多继承吗?为什么
继承好处
- 代码复用,子类直接使用父类属性和方法;
- 扩展功能,子类可重写父类方法,新增自身逻辑;
- 体现层级关系,符合现实世界逻辑。
Java不支持多继承
- 原因:避免菱形继承问题(多个父类有同名方法,子类无法确定调用哪个);
- 替代方案:接口多实现,接口无方法实现,无冲突。
4. 多态的实现条件是什么?静态多态和动态多态的区别
多态实现条件
- 存在继承/实现关系;
- 子类重写父类/接口方法;
- 父类引用指向子类对象(向上转型)。
静态vs动态多态
- 静态多态(编译期) :方法重载,编译期确定调用方法,根据参数列表区分;
- 动态多态(运行期) :方法重写,运行期根据对象实际类型确定调用方法。
5. 抽象类和接口的区别?使用场景
| 特性 | 抽象类(abstract class) | 接口(interface) |
|---|---|---|
| 继承/实现 | 单继承 | 多实现 |
| 方法实现 | 可包含抽象+非抽象方法 | JDK8+:抽象+默认+静态方法 |
| 成员变量 | 任意类型 | 默认为public static final |
| 构造方法 | 有 | 无 |
使用场景
- 抽象类:多个类有共同属性和行为,需要复用代码;
- 接口:定义规范/契约,不关心实现,多个类可实现同一规范。
6. 重写(Override)和重载(Overload)的区别
| 特性 | 重写(Override) | 重载(Overload) |
|---|---|---|
| 位置 | 父子类/接口实现类 | 同一个类 |
| 方法名 | 相同 | 相同 |
| 参数列表 | 相同 | 不同(个数/类型/顺序) |
| 返回值 | 相同或子类 | 无关 |
| 修饰符 | 不能更严格 | 无关 |
| 时期 | 运行期(动态) | 编译期(静态) |
7. this和super的区别
- this :
- 指向当前对象,访问当前类的属性、方法、构造方法;
- 调用本类构造:
this(参数),必须在构造方法第一行。
- super :
- 指向父类对象,访问父类的属性、方法、构造方法;
- 调用父类构造:
super(参数),必须在子类构造第一行。
8. 构造方法的特点?构造方法可以重载吗?可以重写吗
构造方法特点
- 方法名与类名完全相同;
- 无返回值,不写void;
- 创建对象时自动执行,用于初始化对象;
- 无参构造默认存在,定义有参构造后默认无参构造消失。
重载/重写
- 可以重载:多个构造方法,参数列表不同;
- 不能重写:构造方法属于类,子类无法继承,无法重写。
9. 什么是内部类?内部类有哪几种?各自特点
内部类:定义在类内部的类,可访问外部类私有成员,增强封装。
- 成员内部类:类内方法外,无static,可访问外部类所有成员;
- 静态内部类:static修饰,仅访问外部类静态成员;
- 局部内部类:方法内,作用域仅限当前方法;
- 匿名内部类:无类名,一次性使用,简化接口/抽象类实现。
10. 什么是单例模式?懒汉式、饿汉式实现+优缺点
单例模式:保证一个类只有一个实例,提供全局访问点,适用于配置类、线程池。
1. 饿汉式(立即加载)
java
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
- 优点:线程安全、实现简单、无锁效率高;
- 缺点:类加载即创建,浪费内存(不用也创建)。
2. 懒汉式(延迟加载)
java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
- 优点:延迟加载,用到才创建,节省内存;
- 缺点:synchronized加锁,多线程效率低。
三、集合框架
1. Java集合框架整体结构?Collection和Map的区别
整体结构
- 单列集合:
Collection(List、Set、Queue); - 双列集合:
Map(HashMap、TreeMap、ConcurrentHashMap)。
Collection vs Map
- Collection:存储单个对象,有序/无序、可重复/不可重复;
- Map:存储键值对(Key-Value),Key唯一,Value可重复。
2. ArrayList和LinkedList的区别?底层实现
| 特性 | ArrayList | LinkedList |
|---|---|---|
| 底层实现 | 动态数组 | 双向链表 |
| 访问效率 | 高(随机访问) | 低(遍历查找) |
| 增删效率 | 末尾快,中间慢 | 首尾快,中间慢 |
| 内存占用 | 连续内存,占用少 | 节点存数据+地址,占用多 |
| 线程安全 | 不安全 | 不安全 |
适用场景
- ArrayList:频繁查询、少量增删;
- LinkedList:频繁首尾增删、少量查询。
3. HashMap底层实现原理?JDK1.7和1.8的区别
底层原理
- 数据结构:数组+链表+红黑树(JDK1.8);
- 存储:通过Key的hashCode计算数组下标,冲突则用链表/红黑树存储;
- 扩容:负载因子0.75,容量达到
阈值=容量*0.75时扩容为2倍。
JDK1.7 vs 1.8
| 特性 | JDK1.7 | JDK1.8 |
|---|---|---|
| 结构 | 数组+链表 | 数组+链表+红黑树 |
| 链表插入 | 头插法 | 尾插法 |
| 树化条件 | 无 | 链表长度≥8且数组长度≥64 |
| 扩容效率 | 低(rehash易死链) | 高(优化rehash) |
4. HashSet底层实现?如何保证元素不重复
- 底层:基于HashMap实现,元素存为HashMap的Key,Value固定为Object;
- 去重原理:
- 先比较hashCode,不同则直接存储;
- hashCode相同,再用equals比较,不同则存储,相同则覆盖。
5. TreeMap和HashMap的区别?TreeMap排序规则
| 特性 | TreeMap | HashMap |
|---|---|---|
| 底层 | 红黑树 | 数组+链表+红黑树 |
| 有序性 | Key有序 | 无序 |
| 线程安全 | 不安全 | 不安全 |
| 性能 | 增删改查O(logn) | 平均O(1),最差O(logn) |
TreeMap排序规则
- 自然排序:Key实现Comparable接口,重写compareTo;
- 定制排序:创建TreeMap时传入Comparator比较器。
6. ConcurrentHashMap底层实现?线程安全吗?HashMap/HashTable
底层实现
- JDK1.7:分段锁(Segment),每段独立加锁,并发高;
- JDK1.8:CAS+synchronized,锁粒度为数组节点,效率更高。
线程安全
通过锁分段/CAS+synchronized保证线程安全,支持高并发。
三者区别
| 特性 | HashMap | HashTable | ConcurrentHashMap |
|---|---|---|---|
| 线程安全 | 不安全 | 安全(全表synchronized) | 安全(高并发) |
| 效率 | 高 | 低 | 中高 |
| Key/Value | 允许null | 不允许null | 不允许null |
7. 集合遍历方式有哪些?迭代器(Iterator)特点
遍历方式
- 普通for循环:通过索引遍历,适用于List;
- 增强for循环:简化遍历,底层是Iterator;
- 迭代器Iterator:通用遍历方式,支持遍历中删除;
- Lambda表达式:JDK8+,简洁高效。
Iterator特点
- 通用遍历接口,所有Collection集合都支持;
- fail-fast机制:遍历中集合被修改,抛出ConcurrentModificationException;
- 仅支持单向遍历,安全删除元素。
四、IO流与异常
1. Java IO流分类?字节流和字符流的区别
IO分类
- 按数据单位:字节流 (8位)、字符流(16位);
- 按流向:输入流、输出流;
- 按功能:节点流、处理流(缓冲流、转换流)。
字节流vs字符流
| 特性 | 字节流(InputStream/OutputStream) | 字符流(Reader/Writer) |
|---|---|---|
| 处理数据 | 所有文件(图片、视频、文本) | 纯文本文件 |
| 编码 | 不处理编码 | 自动处理Unicode编码 |
| 常用类 | FileInputStream、FileOutputStream | FileReader、FileWriter |
2. 常用IO流实现类
- 字节节点流:FileInputStream、FileOutputStream;
- 字符节点流:FileReader、FileWriter;
- 缓冲流:BufferedInputStream、BufferedReader、BufferedWriter;
- 转换流:InputStreamReader、OutputStreamWriter(字节→字符);
- 对象流:ObjectInputStream、ObjectOutputStream(序列化)。
3. 缓冲流作用?原理
作用
提升IO效率,减少磁盘读写次数。
原理
- 内部维护缓冲区数组,先将数据读入缓冲区,满了再一次性写入磁盘;
- 避免逐字节读写,大幅提升性能。
4. 异常处理方式?throw和throws区别
异常处理方式
- try-catch-finally:捕获并处理异常,程序继续运行;
- throws:声明异常,将异常抛给上层调用者处理;
- throw:手动抛出异常对象。
throw vs throws
| 特性 | throw | throws |
|---|---|---|
| 位置 | 方法体内 | 方法声明后 |
| 内容 | 抛出异常对象 | 声明异常类型 |
| 次数 | 抛出一个 | 可声明多个 |
| 作用 | 手动触发异常 | 通知调用者处理异常 |
5. 自定义异常实现方式?为什么要自定义
实现方式
- 继承Exception (编译时异常)或RuntimeException(运行时异常);
- 提供无参/有参构造方法,调用父类构造。
java
public class MyException extends RuntimeException {
public MyException(String message) { super(message); }
}
自定义原因
- 区分业务异常和系统异常,语义清晰;
- 统一异常处理,便于定位问题;
- 自定义异常信息,更贴合业务。
五、多线程
1. Java创建线程的三种方式+步骤+优缺点
- 继承Thread类
- 步骤:继承Thread→重写run()→new对象→start()启动;
- 优点:简单;缺点:单继承限制,无法继承其他类。
- 实现Runnable接口
- 步骤:实现Runnable→重写run()→new Thread(任务)→start();
- 优点:避免单继承,资源共享;缺点:无返回值。
- 实现Callable接口
- 步骤:实现Callable→重写call()→FutureTask包装→new Thread→start();
- 优点:有返回值、可抛异常;缺点:实现复杂。
2. 线程生命周期状态+转换
线程6种状态:新建、就绪、运行、阻塞、等待、终止
- 新建:new Thread(),未启动;
- 就绪:start(),等待CPU调度;
- 运行:获得CPU,执行run();
- 阻塞:等待锁、IO,释放CPU;
- 等待:wait()/join(),需唤醒;
- 终止:run()执行完毕/异常退出。
3. synchronized作用?修饰内容+底层原理
作用
保证线程安全,实现原子性、可见性、有序性,防止多线程并发冲突。
修饰内容
- 修饰实例方法:锁当前对象;
- 修饰静态方法:锁类对象;
- 修饰代码块:锁指定对象。
底层原理
- 方法:ACC_SYNCHRONIZED标识;
- 代码块:monitorenter/monitorexit指令,依赖JVM的Monitor锁。
4. volatile关键字作用?能保证原子性吗
作用
- 保证可见性:线程修改值立即同步到主内存,其他线程可见;
- 禁止指令重排:保证代码执行顺序。
不能保证原子性
- 原因:volatile仅保证单次读/写原子性,复合操作(i++)不原子;
- 场景:适合状态标记量(如停止标志),不适合计数。
5. 线程池核心参数?创建方式
核心参数
- corePoolSize:核心线程数,常驻线程;
- maximumPoolSize:最大线程数;
- keepAliveTime:非核心线程空闲时间;
- unit:时间单位;
- workQueue:阻塞队列;
- threadFactory:线程工厂;
- handler:拒绝策略。
创建方式
- Executors工具类(不推荐,易OOM);
- new ThreadPoolExecutor()(推荐,自定义参数)。
6. Callable和Runnable的区别?FutureTask作用
Callable vs Runnable
| 特性 | Runnable | Callable |
|---|---|---|
| 方法 | run() | call() |
| 返回值 | 无 | 有 |
| 异常 | 不抛异常 | 可抛受检异常 |
FutureTask作用
- 包装Callable任务,实现Runnable+Future接口;
- 接收call()返回值,通过get()获取结果,支持异步获取。
六、框架与数据库
1. Spring核心思想?IOC和AOP
- 核心思想:IOC(控制反转)、AOP(面向切面编程)。
- IOC:将对象创建、依赖注入交给Spring容器管理,无需手动new,降低耦合;
- AOP:横向抽取通用逻辑(日志、事务),不修改业务代码,实现功能增强。
2. Spring IOC原理?Bean生命周期
IOC原理
- 扫描配置类/XML,解析Bean定义;
- 实例化Bean(反射创建对象);
- 依赖注入(填充属性);
- 初始化Bean(执行初始化方法);
- 容器关闭,销毁Bean。
Bean生命周期
实例化→属性填充→初始化→使用→销毁。
3. MyBatis核心组件?#{}和${}区别
核心组件
- SqlSessionFactory:会话工厂;
- SqlSession:数据库会话;
- Mapper接口:数据操作接口;
- 映射文件:SQL语句配置。
#{} / ${}
- #{} :预编译,防止SQL注入,参数用?占位;
- ${} :字符串拼接,有SQL注入风险,适用于动态表名/列名。
4. SQL基本操作?索引作用
基本操作
- 增:INSERT INTO 表 VALUES(值);
- 删:DELETE FROM 表 WHERE 条件;
- 改:UPDATE 表 SET 字段=值 WHERE 条件;
- 查:SELECT 字段 FROM 表 WHERE 条件。
索引作用
- 加快查询速度,减少全表扫描;
- 缺点:增删改效率降低,占用磁盘空间。
5. InnoDB和MyISAM区别?主键外键作用
InnoDB vs MyISAM
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务支持 | 支持 | 不支持 |
| 锁机制 | 行锁 | 表锁 |
| 外键 | 支持 | 不支持 |
| 崩溃恢复 | 支持 | 不支持 |
主键/外键作用
- 主键:唯一标识表中记录,非空、唯一;
- 外键:关联两张表,保证数据一致性,防止脏数据。
七、综合
1. Java8新特性?Lambda、Stream作用
新特性
- Lambda表达式;
- Stream API;
- 函数式接口;
- 默认方法/静态方法;
- Optional;
- 新日期API。
Lambda/Stream作用
- Lambda:简化匿名内部类,简化代码,支持函数式编程;
- Stream:对集合数据高效操作(过滤、排序、映射),支持并行流。
2. 什么是微服务?Spring Boot和Spring Cloud区别
- 微服务:将单体应用拆分为多个独立、可部署的小型服务,服务间通过API通信,高可用、易扩展。
Spring Boot vs Spring Cloud
- Spring Boot:快速构建单体应用,简化配置,内嵌容器;
- Spring Cloud:微服务生态,基于Spring Boot,提供服务注册、配置、熔断等微服务组件。