1. ==和 equals() 的区别?**
- ==:比较两个对象的内存地址是否相同(对于基本类型比较值,引用类型比较地址)。
- equals() :默认行为与 == 相同(比较地址)。但通常会被类(如
String,Integer)重写,用于比较两个对象的逻辑内容是否相等。
2. String, StringBuilder,和 StringBuffer的区别?
- String:不可变字符序列。任何修改都会产生新对象。线程安全。
- StringBuffer:可变字符序列。修改发生在原对象上。方法用 synchronized修饰,线程安全,但效率较低。
StringBuilder:可变字符序列。StringBuffer的非线程安全版本,效率更高。单线程环境下首选。
3. 重写(Override)和重载(Overload)的区别?
- 重写:子类重新定义父类中已有方法的方法体。要求方法名、参数列表、返回类型都相同。遵循“两同两小一大”原则(运行时多态)。
- 重载:在同一个类中,有多个方法名相同但参数列表不同(类型、个数、顺序)的方法。与返回类型无关(编译时多态)。
4. Java 中基本数据类型有哪些?它们对应的包装类是什么?
byte->Byteshort->Shortint->Integerlong->Longfloat->Floatdouble->Doublechar->Characterboolean->Boolean
5. final, finally, finalize 的区别?
final:修饰符。修饰类(不可继承)、方法(不可重写)、变量(常量,值不可改变)。finally:异常处理关键字。与try-catch一起使用,定义一段无论是否发生异常都会执行的代码,常用于释放资源。finalize():Object 类的一个方法。垃圾回收器在回收对象之前会调用此方法,但不推荐依赖它来释放资源,因为调用时机不确定。
6. ArrayList 和 LinkedList 的区别?
ArrayList:基于动态数组。查询快(通过索引随机访问,O(1)),增删慢(需要移动元素,O(n))。LinkedList:基于双向链表。增删快(只需要修改指针,O(1)),查询慢(需要遍历链表,O(n))。
7. HashMap 的工作原理是什么?
- 存储结构:数组 + 链表/红黑树(JDK1.8+)。
put()过程:计算 key 的hashCode()-> 通过哈希函数得到数组下标 -> 如果该位置为空,直接放入 -> 如果不为空,比较 key(equals())-> 如果相同则覆盖,不同则以链表形式存放(链表长度超过8且数组长度超过64时,链表转红黑树)。get()过程:类似put(),找到对应位置后,遍历链表或树来查找 key。
8. HashSet 是如何保证元素不重复的?
HashSet 内部使用 HashMap 来存储元素。添加元素时,将元素作为 HashMap 的 key 存储,而 value 是一个固定的 Object 常量。由于 HashMap 的 key 是唯一的,所以 HashSet 的元素自然就是唯一的。
9. ConcurrentHashMap 是如何保证线程安全的?
- JDK 1.7:使用分段锁(Segment),将数据分成一段一段存储,每段配一把锁,允许多个线程访问不同段的数据,从而提高并发度。
- JDK 1.8及以后:摒弃了分段锁,采用
synchronized+CAS操作来保证线程安全。锁的粒度更细,只锁住数组的单个桶(链表或树的头节点),并发性能更高。
10. 创建线程有哪几种方式?
- 继承
Thread类,重写run()方法。 - 实现
Runnable接口,实现run()方法(更推荐,因为避免了单继承的局限性)。 - 实现
Callable接口,实现call()方法(可以有返回值,可以抛出异常)。 - 使用线程池(如
ExecutorService),这是最推荐的方式,利于资源复用和管理。
11. sleep() 和 wait() 的区别?
- 所属类:
sleep()是Thread的静态方法;wait()是Object的实例方法。 - 锁释放:
sleep()不释放当前持有的锁;wait()会释放锁,以便其他线程可以进入同步代码块。 - 使用范围:
sleep()可以在任何地方使用;wait()必须在同步方法或同步块(synchronized)中使用。 - 唤醒机制:
sleep()时间到自动唤醒;wait()需要被notify()/notifyAll()唤醒。
12. synchronized 和 ReentrantLock 的区别?
- 本质:
synchronized是 JVM 层面的关键字;ReentrantLock是 JDK 层面的类。 - 使用:
synchronized不需要手动释放锁;ReentrantLock必须手动lock()和unlock(),通常在finally块中解锁。 - 功能:
ReentrantLock功能更丰富,支持公平锁、可轮询的锁等待(tryLock())、条件变量(Condition)等。
13. 什么是死锁?如何避免死锁?
-
死锁:两个或以上的线程互相持有对方所需的资源,导致它们都无法继续执行。
-
必要条件:互斥、请求与保持、不剥夺、循环等待。
-
避免方法:
- 破坏循环等待:按固定的顺序申请锁。
- 破坏请求与保持:一次性申请所有需要的资源。
- 使用
tryLock():尝试获取锁,失败则释放已获得的锁。
14. Java 内存区域(运行时数据区)有哪些?
- 线程私有:程序计数器、Java 虚拟机栈、本地方法栈。
- 线程共享:堆(存放对象实例)、方法区(存放类信息、常量、静态变量等。JDK8+中为元空间)。
- 直接内存:不属于JVM运行时数据区,但也被频繁使用(如NIO)。
15. 简述 Java 的垃圾回收机制(GC)。
GC 主要针对堆内存。它自动回收不再被引用的对象(垃圾),释放内存。
-
如何判断对象可回收?
- 引用计数法(Java未采用):存在循环引用问题。
- 可达性分析(Java采用):从一系列“GC Roots”对象开始向下搜索,走过的路径叫引用链。如果一个对象到GC Roots没有任何引用链相连,则证明此对象不可用。
-
常见的垃圾收集器:Serial, Parallel, CMS, G1, ZGC。
16. 什么是类加载器?双亲委派模型是什么?
-
类加载器:负责将
.class文件加载到JVM中,并生成对应的Class对象。 -
双亲委派模型:
- 一个类加载器收到加载请求后,不会自己先加载,而是委派给父类加载器去完成。
- 只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
-
好处:保证了Java核心库的类型安全(如无论哪个加载器加载
java.lang.Object,最终都是同一个核心类)。
17. String s = new String("abc"); 创建了几个对象?
1个或2个。
- 如果字符串常量池中已存在
"abc",则只在堆上创建1个new String对象。 - 如果字符串常量池中不存在
"abc",则会先在常量池中创建1个"abc"对象,然后在堆上再创建1个new String对象,共2个。
18. 抽象类(Abstract Class)和接口(Interface)的区别?
- 抽象类:
abstract修饰。可以包含抽象方法和具体实现。有构造器。只能单继承。成员变量可以是各种类型。 - 接口:
interface修饰。JDK8前只能有抽象方法,JDK8+后可以有default和静态方法。没有构造器。可以多实现。成员变量默认是public static final的。
19. 什么是反射?有什么应用场景?
- 反射:在运行时动态获取类的所有信息(属性、方法、构造器等)并可以动态操作对象的能力。
- 核心API:
Class,Field,Method,Constructor。 - 应用场景:Spring框架的IoC容器、动态代理、IDE的代码提示、JDBC加载驱动等。
20. try-with-resources 是什么?
JDK7引入的语法糖,用于自动关闭资源。任何实现了 AutoCloseable 接口的资源(如 InputStream, Connection),都可以在 try 后的括号中声明,无需在 finally 中手动关闭。
java
// 传统方式,需要在finally中手动关闭
try (FileInputStream fis = new FileInputStream("file.txt")) {
// use the resource
} catch (IOException e) { // 资源会自动关闭
e.printStackTrace();
}
数据库表是如何设计的?有没有遇到复杂的查询场景?你是怎么优化SQL或数据库结构的?
-
复杂场景: “遇到过最复杂的场景是运营后台需要根据多条件(时间范围、商品名称、用户ID、订单状态)进行分页查询和汇总统计。”
-
优化手段:
- 索引优化:针对高频查询条件建立了联合索引(如
(status, create_time))。 - SQL优化:避免使用
SELECT *,只获取需要的字段;使用EXPLAIN分析执行计划,避免全表扫描和文件排序(Using filesort)。 - 归档和历史表:将超过3个月的订单数据迁移到历史表,保证主表的数据量级在一个可控范围内。
- 索引优化:针对高频查询条件建立了联合索引(如
项目中是否使用了缓存(如Redis)?用在什么场景?如何保证缓存与数据库的数据一致性?
-
应用场景: “广泛使用。主要用在:1. 用户会话(Session)存储;2. 热点商品信息和首页数据的缓存;3. 分布式锁(如防止重复下单);4. 秒杀库存的预扣减。”
-
一致性策略(核心) : “采用最常用的
Cache-Aside(旁路缓存)模式。”-
1、什么是 Cache-Aside 模式?
核心思想:应用程序直接与缓存和数据库对话。缓存不是作为数据库的透明代理,而是由应用程序代码显式地管理。
-
旁路”** 的含义:缓存位于数据库的“旁边”,应用程序按需从缓存中获取数据,如果缓存没有,再去数据库找。
-
- 读流程:先读缓存,命中则返回;未命中则读数据库,然后将数据写入缓存。
- 写流程:先更新数据库,然后删除缓存(而非更新缓存)。
-
-
“为什么是删除而不是更新?主要是为了避免并发写操作导致的缓存数据覆盖和时序错乱问题。