

✨博客主页: https://blog.csdn.net/m0_63815035?type=blog
💗《博客内容》:大数据、AI开发、Java、测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识
📢博客专栏: https://blog.csdn.net/m0_63815035/category_11954877.html
📢欢迎点赞 👍 收藏 ⭐留言 📝
📢本文为学习笔记资料,如有侵权,请联系我删除,疏漏之处还请指正🙉
📢大厦之成,非一木之材也;大海之阔,非一流之归也✨

目录
-
- [第一部分:异常机制(Exception Handling)](#第一部分:异常机制(Exception Handling))
-
- [1. 异常的概念与必要性](#1. 异常的概念与必要性)
- [2. 异常的层次结构](#2. 异常的层次结构)
- [3. 异常的产生与传播](#3. 异常的产生与传播)
- [4. 异常处理方式](#4. 异常处理方式)
-
- 方式一:try-catch-finally
- [方式二:throws 声明抛出](#方式二:throws 声明抛出)
- [throw 关键字(手动抛出)](#throw 关键字(手动抛出))
- [5. finally 与 return 的纠缠(经典面试题)](#5. finally 与 return 的纠缠(经典面试题))
- [6. try-with-resources(JDK7+)](#6. try-with-resources(JDK7+))
- [7. 异常链(Exception Chaining)](#7. 异常链(Exception Chaining))
- [8. 自定义异常](#8. 自定义异常)
- [9. 常见运行时异常及避免方法](#9. 常见运行时异常及避免方法)
- [10. 异常处理最佳实践](#10. 异常处理最佳实践)
- 第二部分:常用类详解
-
- [1. Object 类(所有类的根)](#1. Object 类(所有类的根))
-
- [1.1 toString()](#1.1 toString())
- [1.2 equals()](#1.2 equals())
- [1.3 hashCode()](#1.3 hashCode())
- [1.4 clone() 与 Cloneable 接口](#1.4 clone() 与 Cloneable 接口)
- [1.5 getClass() 和 finalize()](#1.5 getClass() 和 finalize())
- [2. 包装类(Wrapper Class)](#2. 包装类(Wrapper Class))
-
- [2.1 基本对应关系](#2.1 基本对应关系)
- [2.2 构造与转换(以 Integer 为例)](#2.2 构造与转换(以 Integer 为例))
- [2.3 自动装箱与拆箱(编译器语法糖)](#2.3 自动装箱与拆箱(编译器语法糖))
- [2.4 缓存池](#2.4 缓存池)
- [2.5 常用常量与方法](#2.5 常用常量与方法)
- [3. 时间处理类](#3. 时间处理类)
-
- [3.1 旧版 Date & Calendar(线程不安全,不推荐)](#3.1 旧版 Date & Calendar(线程不安全,不推荐))
- [3.2 Java 8 新时间 API(推荐)](#3.2 Java 8 新时间 API(推荐))
- [4. 数组(Array)](#4. 数组(Array))
-
- [4.1 内存结构](#4.1 内存结构)
- [4.2 创建与初始化](#4.2 创建与初始化)
- [4.3 多维数组(非规则数组)](#4.3 多维数组(非规则数组))
- [4.4 Arrays 工具类(java.util.Arrays)](#4.4 Arrays 工具类(java.util.Arrays))
- [4.5 数组复制与扩容](#4.5 数组复制与扩容)
- [5. 字符串(String)](#5. 字符串(String))
-
- [5.1 String 的不可变性](#5.1 String 的不可变性)
- [5.2 字符串常量池](#5.2 字符串常量池)
- [5.3 常用方法](#5.3 常用方法)
- [5.4 StringBuilder / StringBuffer](#5.4 StringBuilder / StringBuffer)
- [6. Math 类](#6. Math 类)
- [7. File 类(java.io.File)](#7. File 类(java.io.File))
-
- [7.1 构造](#7.1 构造)
- [7.2 常用方法](#7.2 常用方法)
- [7.3 递归遍历目录](#7.3 递归遍历目录)
- [8. 枚举(Enum)](#8. 枚举(Enum))
-
- [8.1 基本用法](#8.1 基本用法)
- [8.2 枚举的本质](#8.2 枚举的本质)
- [8.3 带字段和构造器的枚举](#8.3 带字段和构造器的枚举)
- [8.4 枚举实现接口](#8.4 枚举实现接口)
- [8.5 枚举的单例模式](#8.5 枚举的单例模式)
- [8.6 EnumSet 和 EnumMap(性能高效)](#8.6 EnumSet 和 EnumMap(性能高效))
- 总结
本章主要涵盖 Java 异常处理的完整机制,以及日常开发中最常用的类:Object、包装类、时间处理、数组、字符串、Math、File、枚举。感谢大家观看
第一部分:异常机制(Exception Handling)
1. 异常的概念与必要性
异常(Exception)是指程序在运行时发生的非正常情况,如除零、数组越界、文件找不到、网络中断等。如果没有异常处理,程序会直接崩溃。异常机制让程序在遇到问题时能够:
- 捕获 异常并做出合理响应(如提示用户、记录日志)
- 清理 资源(关闭文件、数据库连接)
- 平稳退出 或尝试其他路径
2. 异常的层次结构
Java 中所有异常都继承自 java.lang.Throwable 类。
Throwable
├── Error // 严重错误,程序无法处理
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── ...
└── Exception // 需要处理的异常
├── RuntimeException // 运行时异常(非受检异常)
│ ├── NullPointerException
│ ├── ArithmeticException
│ ├── ArrayIndexOutOfBoundsException
│ ├── ClassCastException
│ ├── IllegalArgumentException
│ └── ...
└── 其他 Exception // 受检异常(Checked Exception)
├── IOException
├── SQLException
├── ParseException
└── ...
关键区别:
- Error :JVM 内部错误、资源耗尽等,应用程序无法恢复,通常不处理(例如
OutOfMemoryError你 catch 了也救不回来)。 - RuntimeException:编译器不强制处理,通常由编程错误引起(如空指针、除数零)。应当通过改进代码逻辑避免,而不是用 try-catch 掩盖。
- Checked Exception:编译器强制要求处理(要么 try-catch,要么 throws),代表外部不可控因素(文件不存在、网络故障)。
3. 异常的产生与传播
java
public class Demo {
public static void main(String[] args) {
method1();
}
static void method1() {
method2();
}
static void method2() {
int a = 10 / 0; // 这里产生 ArithmeticException
}
}

过程:
- 在
method2执行到10/0时,JVM 检测到除零错误,创建一个ArithmeticException对象。 - 当前方法没有
catch该异常,异常对象被抛给调用者method1。 method1也没有处理,继续抛给main。main也没有处理,最终抛给 JVM,JVM 打印异常栈并终止程序。
4. 异常处理方式
方式一:try-catch-finally
java
try {
// 可能抛出异常的代码块
} catch (SomeException e) {
// 处理该异常
} catch (AnotherException e) {
// 可以有多个 catch
} finally {
// 无论是否发生异常都会执行(除了 System.exit())
}
详细规则:
- try 块:一旦发生异常,后面的代码立即停止,跳转到对应的 catch。
- catch 块 :可以有多个,但最多只有一个会被执行 。顺序必须从子类到父类(否则子类永远没机会执行,编译错误)。
- finally 块 :总是执行,适合释放资源(关闭文件、socket、数据库连接)。唯一不执行的情况:在 try 或 catch 中调用了
System.exit()。 - try 可以没有 catch,但必须有 finally(即 try-finally 结构,用于保证资源释放,但异常会向上抛)。
java
// try-finally 示例
InputStream is = null;
try {
is = new FileInputStream("test.txt");
// 读取操作
} finally {
if (is != null) is.close(); // 确保关闭
}
// 如果发生异常,finally 执行后异常继续向上抛
方式二:throws 声明抛出
在方法签名上声明 throws,表示本方法不处理异常,交给调用者处理。
java
public static void readFile() throws IOException {
FileInputStream fis = new FileInputStream("test.txt");
// ...
}
// 调用者必须处理
public static void main(String[] args) {
try {
readFile();
} catch (IOException e) {
e.printStackTrace();
}
}
注意 :重写方法时,子类方法抛出的异常不能比父类方法抛出的异常更宽泛(即不能抛出父类未声明的受检异常)。
throw 关键字(手动抛出)
可以在代码中主动抛出异常对象。
java
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄必须在0~150之间");
}
5. finally 与 return 的纠缠(经典面试题)
java
public static int test() {
int x = 1;
try {
return x; // ① 暂存返回值 1
} finally {
x = 2; // ② 修改局部变量
}
}
// 结果返回 1,而不是 2
解释:
return x不会立即返回,而是先计算表达式值(1)并暂存。- 执行
finally块。 - 最后返回暂存的值(1)。
特殊情况 :如果 finally 中也含有 return,则会覆盖暂存值。
java
public static int test() {
try {
return 1;
} finally {
return 2; // 会覆盖
}
}
// 返回 2
总结 :避免在 finally 中使用 return,否则会吞掉 try 或 catch 中的异常。
6. try-with-resources(JDK7+)
用于自动关闭实现了 AutoCloseable 接口的资源(如流、数据库连接)。
java
try (FileInputStream fis = new FileInputStream("test.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
// 使用资源
} catch (IOException e) {
e.printStackTrace();
}
// 无需显式 close,自动调用
等价于 try-finally 写法,更简洁安全。
7. 异常链(Exception Chaining)
在捕获一个异常后,抛出另一个异常,同时保留原始异常信息。
java
try {
// 底层操作
} catch (SQLException e) {
throw new ServiceException("业务异常", e); // 第二个参数是 cause
}
可通过 e.getCause() 获取原始异常。
8. 自定义异常
何时自定义 :当 JDK 内置异常不足以表达业务语义时(如 InsufficientBalanceException、UserNotFoundException)。
步骤:
java
// 受检异常
public class MyCheckedException extends Exception {
public MyCheckedException() {}
public MyCheckedException(String message) {
super(message);
}
public MyCheckedException(String message, Throwable cause) {
super(message, cause);
}
}
// 非受检异常(常用)
public class MyRuntimeException extends RuntimeException {
public MyRuntimeException(String message) {
super(message);
}
}
建议:
- 如果是业务逻辑错误,通常继承
RuntimeException,避免强迫调用者处理。 - 如果是外部因素可恢复的(如重试),可以继承
Exception。
9. 常见运行时异常及避免方法
| 异常 | 常见原因 | 避免方法 |
|---|---|---|
NullPointerException |
调用 null 对象的方法/属性 | 调用前判空,或用 Optional |
ArrayIndexOutOfBoundsException |
访问数组越界 | 确保索引在 0~length-1 |
ClassCastException |
类型转换失败 | 用 instanceof 检查 |
ArithmeticException |
整数除零 | 检查分母不为0 |
NumberFormatException |
字符串转数字格式错误 | 用正则或 try-catch |
IllegalArgumentException |
参数不合法 | 方法入口做参数校验 |
10. 异常处理最佳实践
- 不要吞异常 :
catch后什么都不做(空 catch)极其糟糕,会掩盖错误。 - 日志记录 :使用
logger.error("xxx", e)打印堆栈。 - 尽早抛出,晚点捕获:底层抛出具体异常,上层统一处理。
- 不要用异常控制正常流程:异常性能差,用 if-else 代替。
- 关闭资源:使用 try-with-resources 或 finally。
- 抛出的异常要合适 :不要抛出
Exception,尽量具体(如IOException)。
第二部分:常用类详解
1. Object 类(所有类的根)
1.1 toString()
默认返回 类名@哈希码,一般需要重写。
java
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
自动调用:System.out.println(obj) 实际调用 obj.toString()。
1.2 equals()
默认比较内存地址(==)。需要比较内容时重写。
重写契约:
- 自反性:
x.equals(x)为 true - 对称性:
x.equals(y)和y.equals(x)结果相同 - 传递性
- 一致性:多次调用结果不变
- 与
null比较返回 false
java
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person p = (Person) obj;
return age == p.age && Objects.equals(name, p.name);
}
1.3 hashCode()
必须与 equals 保持一致:如果 equals 相等,hashCode 必须相等。反之不要求。
java
@Override
public int hashCode() {
return Objects.hash(name, age);
}
作用 :用于哈希集合(HashMap、HashSet)的快速查找。
1.4 clone() 与 Cloneable 接口
Cloneable 是个标记接口(没有方法),指示 Object.clone() 可以合法复制对象。
浅拷贝(默认):
java
class Student implements Cloneable {
String name;
int[] scores;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // 浅拷贝:scores 数组引用相同
}
}
深拷贝:手动复制引用类型字段。
java
@Override
public Object clone() throws CloneNotSupportedException {
Student s = (Student) super.clone();
s.scores = this.scores.clone(); // 数组是引用类型,需要单独克隆
return s;
}
注意 :克隆时如果字段是自定义对象,该对象也需实现 Cloneable。
1.5 getClass() 和 finalize()
getClass():返回运行时类对象(Class实例),用于反射。finalize():垃圾回收前调用,已废弃(从 Java 9 开始)。不推荐使用。
2. 包装类(Wrapper Class)
2.1 基本对应关系
| 基本类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
2.2 构造与转换(以 Integer 为例)
java
// 构造(JDK9 后标记为过时,推荐 valueOf)
Integer i1 = new Integer(10);
Integer i2 = Integer.valueOf(10); // 推荐,有缓存
// 字符串转 Integer
Integer i3 = Integer.valueOf("123");
int i4 = Integer.parseInt("123"); // 返回基本类型
// 包装类转基本类型
int val = i1.intValue();
// 字符串转基本类型
int i5 = Integer.parseInt("456");
2.3 自动装箱与拆箱(编译器语法糖)
java
Integer a = 100; // 实际是 Integer.valueOf(100)
int b = a; // 实际是 a.intValue()
陷阱:
java
Integer n = null;
int m = n; // NullPointerException,因为拆箱调用 n.intValue()
2.4 缓存池
Integer默认缓存-128到127。valueOf()在此范围内返回缓存对象,否则new Integer。Byte、Short、Long也缓存-128~127。Character缓存0~127。Boolean缓存TRUE和FALSE。
java
Integer x = 127;
Integer y = 127;
System.out.println(x == y); // true(缓存)
Integer m = 128;
Integer n = 128;
System.out.println(m == n); // false(超出范围,新对象)
// 解决方案:用 equals 比较
System.out.println(m.equals(n)); // true
2.5 常用常量与方法
java
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.SIZE); // 32(位)
System.out.println(Integer.toBinaryString(10)); // "1010"
3. 时间处理类
3.1 旧版 Date & Calendar(线程不安全,不推荐)
java
Date date = new Date(); // 当前时间
long time = date.getTime(); // 毫秒数
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(date);
Date parsed = sdf.parse("2020-01-01 12:00:00"); // 可能抛 ParseException
问题 :SimpleDateFormat 不是线程安全的,多线程共用需要加锁或使用 ThreadLocal。
3.2 Java 8 新时间 API(推荐)
位于 java.time 包,不可变、线程安全。
核心类:
LocalDate:日期(年-月-日)LocalTime:时间(时:分:秒.纳秒)LocalDateTime:日期+时间ZonedDateTime:带时区的日期时间Instant:时间戳(秒/纳秒)Duration:时间间隔(秒、纳秒)Period:日期间隔(年、月、日)DateTimeFormatter:格式化器
java
// 获取当前时间
LocalDate today = LocalDate.now();
LocalTime nowTime = LocalTime.now();
LocalDateTime now = LocalDateTime.now();
// 指定日期
LocalDate birthday = LocalDate.of(1999, 3, 15);
LocalDateTime dt = LocalDateTime.of(2024, 12, 31, 23, 59, 59);
// 解析与格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(formatter);
LocalDateTime parsed = LocalDateTime.parse("2025-01-01 10:20:30", formatter);
// 日期运算
LocalDate nextWeek = today.plusWeeks(1);
LocalDate twoMonthsAgo = today.minusMonths(2);
LocalDate nextBirthday = birthday.withYear(today.getYear());
if (nextBirthday.isBefore(today)) {
nextBirthday = nextBirthday.plusYears(1);
}
// 时间差
Period period = Period.between(birthday, today);
System.out.println(period.getYears() + "年" + period.getMonths() + "月");
long days = ChronoUnit.DAYS.between(birthday, today);
// Instant 时间戳
Instant nowInstant = Instant.now(); // UTC 时间
long epochSecond = nowInstant.getEpochSecond();
long nano = nowInstant.getNano();
// Duration
Duration d = Duration.between(LocalTime.of(9,0), LocalTime.of(17,30));
System.out.println(d.toHours()); // 8
4. 数组(Array)
4.1 内存结构
java
int[] arr = new int[3];
arr在栈中存储引用,指向堆中一块连续内存区域。- 每个元素有默认初始值(0、0.0、false、
\u0000、null)。 - 引用类型数组存的是对象的引用,对象本身在堆中的其他位置。
4.2 创建与初始化
java
// 静态初始化
int[] a = {1,2,3};
int[] b = new int[]{4,5,6};
// 动态初始化
int[] c = new int[10]; // 元素默认0
String[] d = new String[5]; // 元素默认null
4.3 多维数组(非规则数组)
java
int[][] matrix = new int[3][4]; // 3行4列
int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[4];
jagged[2] = new int[1];
int[][] arr = {{1,2},{3,4,5},{6}};
4.4 Arrays 工具类(java.util.Arrays)
java
// 排序
int[] arr = {3,1,4,1,5,9};
Arrays.sort(arr); // 升序
Arrays.parallelSort(arr); // 并发排序(大数据量)
// 二分查找(必须先排序)
int idx = Arrays.binarySearch(arr, 4);
// 填充
int[] fillArr = new int[10];
Arrays.fill(fillArr, 5); // 全填充5
Arrays.fill(fillArr, 2, 5, 8); // 索引2~4填充8
// 复制
int[] copy = Arrays.copyOf(arr, arr.length);
int[] rangeCopy = Arrays.copyOfRange(arr, 1, 4);
// 比较
boolean eq = Arrays.equals(arr, copy);
boolean deepEq = Arrays.deepEquals(matrix1, matrix2); // 多维
// 转字符串
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.deepToString(matrix));
// 转换为 List(不可修改大小)
List<Integer> list = Arrays.asList(1,2,3);
// 注意:返回的是视图,不能 add/remove,但可以 set
4.5 数组复制与扩容
java
// 手动扩容
int[] old = {1,2,3};
int[] newArr = new int[old.length * 2];
System.arraycopy(old, 0, newArr, 0, old.length);
5. 字符串(String)
5.1 String 的不可变性
String内部使用final char[](Java 9+ 改为byte[])存储,且数组不对外暴露。- 每次修改(如
concat、replace、substring)都会创建新的String对象。
java
String s = "hello";
s = s + " world"; // 实际创建新对象,原 "hello" 变成垃圾
5.2 字符串常量池
- 字面量
"abc"存储在常量池(堆中,JDK7+)。 new String("abc")会在堆中创建新对象,同时常量池中如果不存在也会创建。intern()方法:如果常量池中存在相等字符串,返回常量池引用;否则将当前字符串放入常量池并返回引用。
java
String s1 = "java";
String s2 = new String("java");
System.out.println(s1 == s2); // false
System.out.println(s1 == s2.intern()); // true
JDK 版本差异:
- JDK6:常量池在 PermGen 区域,
intern()复制字符串到永久代。 - JDK7+:常量池移到堆,
intern()只存储引用,不再复制。
5.3 常用方法
java
String str = " Hello World ";
// 长度
int len = str.length();
// 取字符
char ch = str.charAt(6);
// 比较
boolean eq = str.equals("hello world"); // 区分大小写
boolean eqIgnore = str.equalsIgnoreCase("hello world");
int cmp = str.compareTo("Hello"); // 字典序
// 查找
int idx = str.indexOf('o'); // 第一个出现位置
int lastIdx = str.lastIndexOf('o');
boolean contains = str.contains("World");
// 替换
String r1 = str.replace('o', 'a');
String r2 = str.replaceAll("\\s+", ""); // 正则
// 截取
String sub = str.substring(6, 11); // [6,11)
// 分割
String[] parts = str.split("\\s+"); // 按空白分割
// 去首尾空白
String trimmed = str.trim();
// 大小写转换
String upper = str.toUpperCase();
String lower = str.toLowerCase();
// 判断前后缀
boolean starts = str.startsWith(" He");
boolean ends = str.endsWith("ld ");
// 字符串连接
String joined = String.join("-", "a", "b", "c"); // "a-b-c"
// 格式化
String fmt = String.format("姓名:%s,年龄:%d", "张三", 25);
// 转字符数组
char[] chars = str.toCharArray();
// 字符串和基本类型的转换
String numStr = String.valueOf(123);
int num = Integer.parseInt("123");
5.4 StringBuilder / StringBuffer
StringBuilder(非线程安全,速度快)StringBuffer(线程安全,方法有synchronized,速度慢)
常用方法:
java
StringBuilder sb = new StringBuilder(); // 默认容量16
sb.append("hello");
sb.append(' ');
sb.append("world");
sb.insert(5, ",");
sb.delete(5, 6);
sb.replace(0, 5, "HELLO");
sb.reverse();
String result = sb.toString();
性能建议 :在循环内拼接大量字符串时,显式使用 StringBuilder,避免使用 +,因为 + 在循环内会产生大量临时对象。
6. Math 类
所有方法都是 static,主要用于数学运算。
java
// 基本
Math.abs(-10); // 10
Math.max(10,20); // 20
Math.min(10,20); // 10
Math.pow(2,3); // 8.0
Math.sqrt(9); // 3.0
// 取整
Math.ceil(3.2); // 4.0 向上取整
Math.floor(3.9); // 3.0 向下取整
Math.round(3.5); // 4 四舍五入(返回 long)
Math.round(3.4); // 3
// 随机数 [0.0, 1.0)
double r = Math.random();
int dice = (int)(Math.random() * 6) + 1; // 1~6
// 三角函数、对数等
Math.sin(Math.PI/2);
Math.log(10);
Math.exp(1);
7. File 类(java.io.File)
代表文件或目录的路径,并不代表文件内容。
7.1 构造
java
File f1 = new File("D:/test/a.txt");
File f2 = new File("D:/test", "a.txt");
File parent = new File("D:/test");
File f3 = new File(parent, "a.txt");
路径分隔符 :File.separator 跨平台(Windows 是 \,Linux 是 /),建议使用。
7.2 常用方法
java
File f = new File("D:/test/a.txt");
// 判断
f.exists();
f.isFile();
f.isDirectory();
f.isHidden();
f.canRead();
f.canWrite();
// 获取信息
f.getName(); // "a.txt"
f.getPath(); // 构造时的路径
f.getAbsolutePath(); // 绝对路径
f.length(); // 字节数
f.lastModified(); // 最后修改时间(毫秒)
// 创建删除
f.createNewFile(); // 创建新文件,返回 boolean
f.mkdir(); // 创建单级目录
f.mkdirs(); // 创建多级目录
f.delete(); // 删除文件或空目录
f.deleteOnExit(); // JVM 退出时删除
// 目录操作
File dir = new File("D:/test");
String[] names = dir.list(); // 文件名数组
File[] files = dir.listFiles(); // File 对象数组
File[] mp3s = dir.listFiles((d, name) -> name.endsWith(".mp3"));
7.3 递归遍历目录
java
public static void listAll(File dir) {
if (dir == null || !dir.exists()) return;
if (dir.isFile()) {
System.out.println(dir.getAbsolutePath());
} else {
File[] subs = dir.listFiles();
if (subs != null) {
for (File sub : subs) {
listAll(sub);
}
}
}
}
8. 枚举(Enum)
8.1 基本用法
java
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
每个枚举值都是 Season 类的实例,且是唯一的单例。
8.2 枚举的本质
- 隐式继承
java.lang.Enum类,因此不能继承其他类,但可以实现接口。 - 枚举值实际上是
public static final常量。 - 编译器会自动生成
values()和valueOf(String)方法。
java
Season s = Season.SPRING;
System.out.println(s.name()); // "SPRING"
System.out.println(s.ordinal()); // 0(声明顺序)
System.out.println(s.toString()); // "SPRING"(可重写)
8.3 带字段和构造器的枚举
java
public enum Status {
SUCCESS(200, "成功"),
ERROR(500, "服务器错误"),
NOT_FOUND(404, "资源不存在");
private int code;
private String msg;
Status(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() { return code; }
public String getMsg() { return msg; }
public static Status fromCode(int code) {
for (Status s : values()) {
if (s.code == code) return s;
}
return null;
}
}
8.4 枚举实现接口
java
interface Desc {
String getDescription();
}
enum Color implements Desc {
RED {
public String getDescription() { return "红色"; }
},
BLUE {
public String getDescription() { return "蓝色"; }
};
}
8.5 枚举的单例模式
利用枚举的特性(JVM 保证单例、线程安全、防止反射和序列化破坏)。
java
public enum Singleton {
INSTANCE;
public void doSomething() { ... }
}
8.6 EnumSet 和 EnumMap(性能高效)
java
EnumSet<Season> set = EnumSet.of(Season.SPRING, Season.SUMMER);
EnumMap<Season, String> map = new EnumMap<>(Season.class);
map.put(Season.SPRING, "春天");
总结
异常机制:
- 区分 Error、RuntimeException 和 Checked Exception。
- 使用 try-catch-finally 或 throws,推荐 try-with-resources。
- finally 中避免 return。
- 自定义异常时根据场景选择继承 Exception 还是 RuntimeException。
常用类:
- Object 的 toString/equals/hashCode 必须配合重写。
- 包装类注意缓存池和自动装箱的空指针风险。
- 时间处理优先用 java.time 包。
- 数组工具类 Arrays 提供丰富操作。
- String 不可变,拼接多用 StringBuilder。
- File 操作路径注意跨平台分隔符。
- 枚举用于固定常量集合,功能强大。
这些类在日常开发中几乎天天使用,建议结合 JDK 源码加深理解。
csharp
今天这篇文章就到这里了,大厦之成,非一木之材也;大海之阔,非一流之归也。感谢大家观看本文
