文章目录
一、String三兄弟的终极对决(高频必考)
小伙伴们注意啦!!!String、StringBuffer、StringBuilder这三位可是面试官的宠儿。他们的核心差异就藏在两个关键词里:可变性和线程安全(敲黑板!)
- String(不可变类):每次操作都生成新对象(内存警告⚠️)
String str = "hello";
str += " world"; // 这里实际上创建了3个对象!
- StringBuffer(线程安全):适合多线程环境(性能警告⚠️)
StringBuffer sb = new StringBuffer();
sb.append("hello").append(" world"); // 线程安全但速度慢
- StringBuilder(非线程安全):单线程环境首选(速度王者🏆)
StringBuilder sb = new StringBuilder();
sb.append("Java").insert(0, "Hi "); // 比StringBuffer快约30%
重要结论(拿小本本记下):
单线程用StringBuilder,多线程用StringBuffer,字符串不变用String!
二、==和equals()的死亡缠绕
这个知识点看似简单却暗藏杀机(掉坑率高达80%!!!)
- ==运算符:比较内存地址(对象身份证号)
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1 == s2); // false(身份证不同)
- equals()方法:比较对象内容(对象内涵)
System.out.println(s1.equals(s2)); // true(内涵相同)
特殊案例(小心地雷💣):
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(缓存池范围)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(超出缓存池)
三、集合框架全家桶(ArrayList vs LinkedList)
3.1 数组与链表的世纪之战
- ArrayList底层是动态数组(随机访问快)
- LinkedList底层是双向链表(增删效率高)
实战场景分析:
需要频繁根据索引查询 → ArrayList(时间复杂度O(1))
需要频繁在中间插入/删除 → LinkedList(时间复杂度O(1))
3.2 HashMap底层黑科技
JDK1.8的HashMap采用数组+链表+红黑树结构(应对哈希碰撞的终极方案)
加载因子0.75(空间与时间的完美平衡点)
树化阈值8(链表长度超过8转红黑树)
put方法源码精髓(理解这个秒杀一片):
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// ① 判断table是否为空
// ② 计算数组下标 (n-1) & hash
// ③ 处理哈希冲突(链表/红黑树)
// ④ 超过阈值则扩容resize()
}
四、多线程的冰与火之歌
4.1 synchronized vs Lock
比较项 | synchronized | Lock(如ReentrantLock) |
---|---|---|
获取方式 | 自动获取释放 | 需要手动lock/unlock |
锁类型 | 非公平锁 | 可配置公平锁 |
响应中断 | 不支持 | 支持lockInterruptibly() |
条件队列 | 单条件 | 多条件Condition |
4.2 线程池的七大参数(面试必背)
ThreadPoolExecutor(
int corePoolSize, // 核心线程数(常驻部队)
int maximumPoolSize, // 最大线程数(总兵力)
long keepAliveTime, // 空闲线程存活时间(休整时间)
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列(作战指挥部)
ThreadFactory threadFactory, // 线程工厂(兵工厂)
RejectedExecutionHandler handler // 拒绝策略(战损处理)
)
五、JVM内存模型直通车
5.1 运行时数据区(灵魂画手版)
┌─────────────────┐
│ 方法区(Method) │ ← 类信息、常量、静态变量
├─────────────────┤
│ 堆(Heap) │ ← 对象实例(GC主战场)
├─────────────────┤
│ 虚拟机栈(VM Stack)│ ← 方法调用(栈帧/局部变量)
├─────────────────┤
│ 本地方法栈(Native)│ ← Native方法
├─────────────────┤
│ 程序计数器(PC Register)│ ← 当前执行地址
└─────────────────┘
5.2 对象创建全流程(上帝视角)
- 类加载检查 → 2. 分配内存 → 3. 初始化零值
- 设置对象头 → 5. 执行方法
六、异常处理冷知识(90%人不知道)
finally块的执行陷阱:
public static int testFinally() {
try {
return 1;
} finally {
return 2; // 实际返回2!!!
}
}
七、自动装箱的惊天大坑
比较陷阱示例:
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(超出缓存范围)
面试实战技巧(内部资料流出)
当面试官问"你还有什么问题吗?",试试这些杀手锏:
- 贵司的Java技术栈主要用哪些框架?
- 团队目前在技术架构上有哪些挑战?
- 这个岗位最需要哪些核心能力?
记住:面试是双向选择,大胆展示你的技术热情!(但别问薪资福利,等HR环节再说)