文章目录
引言
最近帮朋友公司面了37个Java初级开发,发现80%的候选人对"背答案"如数家珍,但一追问底层原理就集体翻车(太真实了😭)。今天咱们就扒开8个高频但容易翻车的基础题,看完保你下次面试底气十足!
1. String的不可变性是"伪命题"?(
你以为的不可变:String s = "hello"; s = "world"
这不就变了?
实际上的不可变:存储在堆内存里的char[]数组从没被修改过!!!
硬核验证法(
String str = "Hello";
Field valueField = String.class.getDeclaredField("value");
valueField.setAccessible(true);
char[] value = (char[]) valueField.get(str);
value[0] = 'h';
System.out.println(str); // 输出hello还是hello??
(答案揭晓:输出h ello
!反射暴力修改成功,但官方文档说不可变是规范不是强制约束啊喂!)
不可变的三大好处:
- 哈希值缓存不用重复计算(HashMap狂喜)
- 线程安全天然优势(不用加锁美滋滋)
- 字符串常量池省内存(JVM偷着乐)
2. ==和equals的世纪误会
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(比对象地址)
System.out.println(s1.equals(s2)); // true (比内容)
但如果是自定义对象:
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
Person p1 = new Person("张三");
Person p2 = new Person("张三");
System.out.println(p1.equals(p2)); // 输出啥??
(答案是false!因为没重写equals方法时,默认用==比较!!!)
正确重写姿势:
@Override
public boolean equals(Object o) {
// 1. 自检
if (this == o) return true;
// 2. 类型检查
if (!(o instanceof Person)) return false;
// 3. 字段对比
Person person = (Person) o;
return Objects.equals(name, person.name);
}
(别忘了一起重写hashCode(),否则HashMap要出大事!)
3. final关键字的三副面孔
① 变量:
final int x = 10;
x = 20; // 编译报错!(final变量是只读的)
但如果是对象:
final List<String> list = new ArrayList<>();
list.add("hello"); // 可以操作!(final限制的是引用不能变)
② 方法:
class Parent {
final void show() { ... }
}
class Child extends Parent {
void show() { ... } // 编译报错!(final方法禁止重写)
}
③ 类:
final class UtilityClass { ... }
class SubClass extends UtilityClass { ... } // 报错!(final类不可继承)
冷知识:
为什么匿名内部类访问局部变量必须final?
void test() {
int count = 0;
new Thread(() -> {
System.out.println(count); // 报错!需要final修饰
}).start();
}
(因为局部变量生命周期短,而内部类可能存活更久,final保证值不变)
4. 多态背后的"影子武士"
看这段代码:
class Animal {
void eat() { System.out.println("动物吃饭"); }
}
class Cat extends Animal {
void eat() { System.out.println("猫吃鱼"); }
void jump() { System.out.println("猫跳"); }
}
Animal a = new Cat();
a.eat(); // 输出"猫吃鱼"(动态绑定)
a.jump(); // 编译报错!(编译看左边)
JVM如何实现多态?
- 每个类有个虚方法表(vtable)
- 调用方法时查对象的实际类型
- 通过方法表找到具体实现
- 非虚方法(private/static/final)直接解析
(所以用final修饰方法可以提高性能?理论上是,但现代JVM优化后差距可以忽略)
5. 异常处理的三层滤镜
try {
// 可能出问题的代码
} catch (IOException e) {
// 处理IO异常
} catch (Exception e) {
// 处理其他异常
} finally {
// 必须执行的代码
}
必考坑点:
Exception
vsError
:后者是严重错误(如OutOfMemoryError),不用处理- checked异常(必须处理) vs unchecked异常(RuntimeException及其子类)
- finally和return的相爱相杀:
int test() {
try {
return 1;
} finally {
return 2; // 实际返回2!!!
}
}
(finally的return会覆盖try中的返回值,但千万别这么写!)
总结
看完这5道题是不是觉得基础题也不简单?其实面试官最想看到:
- 能清晰表达核心概念
- 能结合实际开发场景
- 能触达底层实现原理
(悄悄说:现在立刻写代码验证本文案例,记忆效果提升300%!)
扩展阅读
- 《Java编程思想》第9章 异常处理
- Oracle官方文档:Java Language Specification
- JVM规范:方法调用章节