一、String的十万个为什么(必考!)
1.1 ==和equals()的"塑料兄弟情"
(注意啦老铁们)这俩货看着像双胞胎,实际根本不是一个妈生的!
String s1 = new String("Hello");
String s2 = new String("Hello");
String s3 = "Hello";
String s4 = "Hello";
System.out.println(s1 == s2); // false(扎心!)
System.out.println(s1.equals(s2)); // true
System.out.println(s3 == s4); // true(惊喜!)
!!!重点来了:
==
比的是内存地址(身份证号)equals()
比的是内容(长相)- 字符串常量池是个VIP休息室,直接赋值的字符串都在这儿候着
1.2 String、StringBuffer、StringBuilder的"三国杀"
(面试官超爱问这个)这三个货的区别就像三种外卖小哥:
String | StringBuffer | StringBuilder | |
---|---|---|---|
可变性 | 石头人 | 橡皮泥 | 橡皮泥Pro |
线程安全 | 无所谓 | 安全标兵 | 独行侠 |
性能 | 最慢 | 中等 | 最快 |
敲黑板!!适用场景:
- 字符串不变:选String(比如数据库连接地址)
- 频繁修改且要线程安全:StringBuffer(银行转账)
- 频繁修改但单线程:StringBuilder(本地日志处理)
二、面向对象三大法宝(OOP核心)
2.1 抽象类 vs 接口的"世纪对决"
这俩的关系就像武侠小说的正邪两派:
// 抽象类版武林秘籍
abstract class KungFu {
abstract void attack(); // 必杀技
void sleep() { // 通用技能
System.out.println("打坐回血");
}
}
// 接口版武功秘籍
interface Magic {
void spell(); // 法术攻击
default void fly() { // 默认技能
System.out.println("御剑飞行");
}
}
!!!区别总结:
- 抽象类是"is-a"关系(比如:李小龙是武术家)
- 接口是"can-do"关系(比如:李小龙会双截棍)
- Java8开始接口也可以有默认方法(真香!)
2.2 多态的"七十二变"
(这个容易栽跟头)看代码:
class Animal {
void speak() {
System.out.println("动物叫");
}
}
class Cat extends Animal {
@Override
void speak() {
System.out.println("喵喵喵");
}
void scratch() {
System.out.println("挠你!");
}
}
public static void main(String[] args) {
Animal myPet = new Cat();
myPet.speak(); // 喵喵喵(正确!)
myPet.scratch(); // 编译报错!(惊不惊喜?)
}
多态三大原则:
- 编译看左边(Animal有的方法才能用)
- 运行看右边(实际执行子类方法)
- 属性没有多态(永远看左边)
三、集合框架的"修罗场"
3.1 ArrayList vs LinkedList的"速度与激情"
(实际开发经常踩坑)这俩的差别就像电动车和跑车:
ArrayList | LinkedList | |
---|---|---|
底层结构 | 动态数组 | 双向链表 |
随机访问 | O(1)(闪电侠) | O(n)(乌龟爬) |
头尾插入 | 慢 | 快 |
内存占用 | 较少 | 较多(每个节点带指针) |
真实案例:某电商平台用ArrayList存百万级订单数据,结果分页查询卡成狗→换成LinkedList更卡→最终用数据库分页+缓存解决(血泪教训!)
3.2 HashMap的"八卦阵"
(面试必问!)JDK8的HashMap结构大升级:
!!!灵魂拷问:
- 为什么链表长度>8转红黑树?(答:统计学概率,泊松分布)
- 扩容机制是怎样的?(答:2倍扩容,rehash)
- 线程安全吗?(答:不是,要用ConcurrentHashMap)
四、异常处理的"求生指南"
4.1 try-with-resources黑科技
(拯救无数程序员)传统写法vs炫酷写法:
// 传统写法(容易漏关流)
FileInputStream fis = null;
try {
fis = new FileInputStream("data.txt");
// 处理文件
} finally {
if (fis != null) {
fis.close(); // 可能又抛异常!
}
}
// 炫酷写法(自动关流)
try (FileInputStream fis = new FileInputStream("data.txt");
ZipInputStream zis = new ZipInputStream(fis)) {
// 自动关闭所有资源
}
!!!使用条件:
- 资源必须实现AutoCloseable接口
- 多个资源按声明顺序反向关闭
五、多线程的"角斗场"
5.1 synchronized的"三重境界"
(并发编程基础)锁的进化史:
// 第一重:普通方法锁
public synchronized void method() {}
// 第二重:代码块锁
public void method() {
synchronized(this) {}
}
// 第三重:类级别锁
public void method() {
synchronized(MyClass.class) {}
}
5.2 volatile的"读心术"
(容易误解的关键字)三大特性:
- 可见性(修改立刻可见)
- 禁止指令重排序
- 不保证原子性(所以不能替代锁)
典型应用场景:状态标志位
class Worker implements Runnable {
private volatile boolean running = true;
public void run() {
while (running) {
// 干活...
}
}
public void stop() {
running = false;
}
}
六、JVM内存模型的"密室逃脱"
6.1 内存结构图
(面试常考脑补题)
┌───────────────────────┐
│ Method Area │
│ (类信息、常量、静态变量) │
├───────────────────────┤
│ Heap │
│ (对象实例) │
├───────────────────────┤
│ Stack │
│ (局部变量、方法调用) │
├───────────────────────┤
│ Program Counter │
│ (线程执行位置) │
├───────────────────────┤
│ Native Method Stack │
│ (本地方法调用) │
└───────────────────────┘
6.2 GC的"垃圾分类"
(调优必备知识)常见垃圾回收算法:
- 标记-清除(会产生内存碎片)
- 复制算法(新生代常用)
- 标记-整理(老年代常用)
- 分代收集(现在JVM主流方案)
七、新特性"尝鲜区"
7.1 Java17的switch表达式
(代码简洁度+++)
// 传统写法
String dayType;
switch (day) {
case MONDAY, FRIDAY -> dayType = "忙day";
case SATURDAY, SUNDAY -> dayType = "躺平";
default -> dayType = "普通";
}
// 炫酷写法
String dayType = switch (day) {
case MONDAY, FRIDAY -> "忙day";
case SATURDAY, SUNDAY -> {
System.out.println("周末啦!");
yield "躺平"; // 注意这里用yield返回值
}
default -> "普通";
};
面试实战技巧(划重点!)
- 遇到不会的问题:可以说"这个知识点我之前主要关注在应用层面,底层实现还需要再研究"(然后偷偷记下来)
- 手写代码时:先问清楚需求边界(比如要不要判空、处理异常)
- 设计题:多问面试官业务场景(并发量?数据规模?)
- 遇到压力面:保持微笑,把知道的清晰表达出来
最后送大家一句话:面试造火箭,工作拧螺丝。但能把螺丝拧出火箭水准的,才是真大佬!觉得有用的朋友记得点个赞(疯狂暗示)~