一、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 -> "普通"; };
面试实战技巧(划重点!)
- 遇到不会的问题:可以说"这个知识点我之前主要关注在应用层面,底层实现还需要再研究"(然后偷偷记下来)
- 手写代码时:先问清楚需求边界(比如要不要判空、处理异常)
- 设计题:多问面试官业务场景(并发量?数据规模?)
- 遇到压力面:保持微笑,把知道的清晰表达出来
最后送大家一句话:面试造火箭,工作拧螺丝。但能把螺丝拧出火箭水准的,才是真大佬!觉得有用的朋友记得点个赞(疯狂暗示)~