目录
14. 内存结构深度解析
内存区域分工
-
栈(Stack):存储方法调用栈帧、局部变量(基本类型值/对象引用地址)
-
堆(Heap):存储所有对象实例(包括字符串常量池)、数组
-
常量池:存储编译期确定的字面量(JDK7后移至堆中)
-
方法区:存储类信息、静态变量(JDK8后由元空间实现)
栈溢出原理
// 无限递归示例
public class StackOverflowDemo {
public static void recursive() {
recursive(); // 每次递归产生新的栈帧
}
public static void main(String[] args) {
recursive(); // StackOverflowError
}
}
原因:每个方法调用创建新栈帧,栈空间耗尽导致溢出
常量池去重验证
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
System.out.println(s1 == s2); // true(指向同一常量)
System.out.println(s1 == s3); // false(堆中新对象)
System.out.println(s1.equals(s3)); // true(内容相同)
15. 异常处理核心机制
finally执行铁律
public class FinallyDemo {
public static void main(String[] args) {
try {
System.out.println("执行代码");
if(true) throw new Exception();
} catch (Exception e) {
System.out.println("捕获异常");
return; // 此处返回前必执行finally
} finally {
System.out.println("资源释放");
}
}
}
输出结果:
执行代码 捕获异常 资源释放
finally vs static块
特性 | finally块 | static块 |
---|---|---|
执行时机 | 异常处理后 | 类加载时 |
主要用途 | 资源释放(文件/数据库连接) | 初始化静态资源 |
执行次数 | 每次try-catch执行 | 仅一次 |
16. 对象比较三剑客
比较机制对比
操作符/方法 | 作用范围 | 比较内容 | 重写建议 |
---|---|---|---|
== | 基本类型 | 值直接比较 | 无需 |
equals() | 引用类型 | 默认地址,可重写 | 必须同时重写hashCode |
hashCode() | 哈希集合 | 对象哈希值 | 保持与equals一致 |
String特殊机制
String str1 = "Fly";
String str2 = new String("Fly").intern(); // 强制使用常量池
System.out.println(str1 == str2); // true(intern保证)
17. 参数传递真相
值传递实验
public class ParamPassing {
public static void main(String[] args) {
// 基本类型测试
int num = 10;
modifyPrimitive(num);
System.out.println("基本类型修改后:" + num); // 输出10
// 引用类型测试
StringBuilder sb = new StringBuilder("原始值");
modifyReference(sb);
System.out.println("引用类型修改后:" + sb); // 输出"原始值-追加"
}
static void modifyPrimitive(int a) {
a = 20; // 不影响实参
}
static void modifyReference(StringBuilder builder) {
builder.append("-追加"); // 修改对象内容
}
}
20. 接口与抽象类终极对比
特性对照表
维度 | 抽象类 | 接口 |
---|---|---|
构造方法 | 可以有 | 不能有 |
方法实现 | 可以有具体方法 | JDK8+支持default/static方法 |
变量类型 | 任意类型 | 默认public static final |
继承方式 | 单继承 | 多实现 |
设计定位 | "是什么"的抽象 | "能做什么"的契约 |
接口新特性示例
public interface Payment {
// 默认方法(可被覆盖)
default void validate() {
System.out.println("执行通用验证逻辑");
}
// 静态工具方法
static String generateTxNo() {
return "TX" + System.currentTimeMillis();
}
}
22. 字符串三兄弟终极对决
性能对比实验
public class StringPerformance {
public static void main(String[] args) {
// 测试String拼接
long start = System.currentTimeMillis();
String result = "";
for (int i = 0; i < 10000; i++) {
result += i; // 产生大量临时对象
}
System.out.println("String耗时:" + (System.currentTimeMillis()-start));
// 测试StringBuilder
start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
sb.append(i);
}
System.out.println("StringBuilder耗时:" + (System.currentTimeMillis()-start));
}
}
选型指南
场景 | 推荐类型 | 理由 |
---|---|---|
少量固定字符串操作 | String | 代码简洁、线程安全 |
单线程大量字符串操作 | StringBuilder | 最高性能 |
多线程字符串操作 | StringBuffer | synchronized保证线程安全 |
配置文件键值 | String | 利用常量池节省内存 |
企业级开发技巧
-
字符串处理黄金法则:
-
循环内字符串拼接必须使用StringBuilder
-
敏感信息处理使用char[]代替String(可及时清空)
-
-
异常处理最佳实践:
try (Connection conn = getConnection(); // 自动关闭资源 PreparedStatement ps = conn.prepareStatement(sql)) { // 业务代码 } catch (SQLException e) { logger.error("数据库操作异常", e); // 使用日志框架记录 throw new BusinessException("服务暂不可用"); }
-
性能监控技巧:
# 查看堆内存使用 jmap -heap <pid> # 分析线程栈 jstack <pid> > thread_dump.log
-
代码安全规范:
-
所有equals比较前进行null检查
-
使用Objects.equals()避免空指针
public boolean safeCompare(Object a, Object b) { return Objects.equals(a, b); }
-
-
并发编程技巧:
-
使用ThreadLocal保存线程私有数据
-
敏感操作添加@Transactional注解保证原子性
-