深入解析Java常量、字面量和枚举
作者:gugucoding
摘要: 本文深入解析 Java 中表示"不变值"的三个核心概念:字面量、常量和枚举。字面量是直接写在代码中的原始数据值;常量通过 final 关键字锁定不可变变量,提高代码可维护性;枚举则用于定义一组有限的、类型安全的固定选项集合。理解这三者的区别与适用场景,有助于编写更清晰、健壮且易于维护的 Java 代码。
上一篇文章里,我们花了很大篇幅聊变量——那些可以变化的量,比如年龄会增长,分数会变化。变量就像是一个水杯,你可以往里面倒不同的水。
但生活中也有些东西是不变的。比如圆周率 π 永远是 3.14159……,一天永远是 24 小时,你的身份证号从出生到离世都不会变。在程序里,我们同样需要表达这些"不变"的值。
今天我们就来聊两个紧密相关的概念:字面量和常量。顺便再认识一下 Java 中一种特殊的"常量集合"——枚举(enum)。
1. 字面量(Literal)—— 直白的"字面意思"
字面量,顾名思义,就是直接写在代码中的值,它本身就已经表达了它的类型和意义。你不需要额外解释,编译器一看就明白。
举个例子,下面这些就是字面量:
int age = 25; // 25 是整数字面量 double pi = 3.14159; // 3.14159 是浮点数字面量 char grade = 'A'; // 'A' 是字符字面量 boolean isPass = true; // true 是布尔字面量 String name = "张三"; // "张三" 是字符串字面量
字面量就是数据本身,它不需要 new,不需要构造方法,直接写出来就行。就像你在纸上写"25",谁都知道这是数字二十五,而不需要写成"整数类型的二十五"。
Java 中常见的字面量有:
| 类型 | 示例 | 说明 |
|---|---|---|
| 整数 | 100、-50、0 | 默认是 int,加 L 后缀是 long |
| 浮点数 | 3.14、-0.5、2.0 | 默认是 double,加 f 后缀是 float |
| 字符 | 'A'、'好'、'\n' | 单引号括起来,可以是转义字符 |
| 布尔 | true、false | 仅这两个值 |
| 字符串 | "Hello"、""(空串) | 双引号括起来 |
| 空引用 | null | 表示引用类型不指向任何对象 |
💡 特别注意:
null是引用类型的字面量,不能赋值给基本类型。比如int a = null;是错误的。
💡 数字可读性(JDK 7+):大数字可以用下划线分隔,例如
int oneBillion = 1_000_000_000;,编译时会自动忽略下划线。
转义字符
字符字面量中,反斜杠 \ 用来表示转义字符——有特殊含义的字符:
| 转义字符 | 含义 |
|---|---|
\n | 换行(New Line) |
\t | 制表符(Tab) |
\" | 双引号 |
\' | 单引号 |
\\ | 反斜杠本身 |
例如:
System.out.println("第一行\n第二行"); // 输出两行
System.out.println("列1\t列2\t列3"); // 用 Tab 对齐
💡 字符串字面量的特殊性:字符串字面量会被编译器自动放入字符串常量池(String Pool)。如果你写
String a = "hello";和String b = "hello";,实际上a和b指向的是同一个对象。这是 Java 为了节省内存做的优化。
2. 常量(Constant)—— 用final锁定的"不变值"
有时候,我们希望一个变量一旦被赋值,就再也不能改变。比如数学中的圆周率、公司名称、税率等。这时候我们就用 final 关键字来声明一个常量。
语法:在变量声明前加上 final 修饰符。
final double PI = 3.1415926535; final String COMPANY_NAME = "星辰科技";
一旦赋值后,再试图修改它,编译器就会报错:
PI = 3.14; // 编译错误:无法为 final 变量 PI 赋值
常量的命名规范
Java 社区约定:常量名全部大写,多个单词之间用下划线 _ 分隔。例如:
MAX_VALUEDEFAULT_TIMEOUTEARTH_RADIUS_KM
这样做的好处是,一眼扫过去就知道它是常量,不会和普通变量混淆。
常量的作用
- 提高可维护性:如果某个值在程序多个地方使用,把它定义为常量,将来只需修改一处即可。
- 增强可读性:
MAX_SIZE比1024更能传达意图。 - 防止意外修改:避免程序在运行时不小心改了不该改的值。
常量的分类
按作用范围,常量可以分为:
- 局部常量:定义在方法内部的常量,只在该方法内有效。必须在声明时初始化。
public void demo() {
final int MAX_RETRIES = 3; // 局部常量:声明时必须初始化
// MAX_RETRIES = 5; // 错误!不能再次赋值
}
- 类常量:定义在类中、方法外,用
static final修饰,属于类本身,所有实例共享。这是我们最常用的常量形式。
public class MathConstants {
public static final double PI = 3.141592653589793;
public static final double E = 2.718281828459045;
}然后在其他地方直接通过 MathConstants.PI 来使用,无需创建对象。
💡
final还有其他高级用法(如修饰方法、类),等我们学到面向对象时再展开。
3. 枚举(Enum)—— 一组固定的"候选值"
有时候,一个变量只能取预先定义好的一组值中的某一个。比如:
- 星期几:只能是 Monday、Tuesday、…、Sunday。
- 季节:Spring、Summer、Autumn、Winter。
- 订单状态:待支付、已支付、已发货、已完成、已取消。
如果用整数或字符串来表示,很容易写错,比如把 "已支付" 错写成 "已付",或者把 3 当成状态,但 3 代表什么只有写代码的人知道。而且编译器无法帮你检查错误。
Java 提供了 枚举(enum) 来解决这个问题。枚举是一种特殊的类,它定义了一个有限的、固定的值集合。
定义枚举
使用 enum 关键字:
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
这里定义了一个 Season 类型,它有且仅有四个值:SPRING、SUMMER、AUTUMN、WINTER。
💡 枚举通常定义在独立的
.java文件中(文件名与枚举名一致),也可以嵌套在类中。初学阶段建议放在独立文件中,方便管理。
使用枚举
Season current = Season.SPRING; System.out.println(current); // 输出 SPRING
枚举可以直接用在 switch 中(我们下篇文章会详细学 switch):
// 下面用到了 switch 语句,下篇会详细讲解,这里只需知道它能根据枚举值执行不同代码
switch (current) {
case SPRING:
System.out.println("春天来了");
break;
case SUMMER:
System.out.println("夏天到了");
break;
// ...
}枚举的优点
- 类型安全:你只能赋值为枚举中定义的值,不能随便赋其他值。
- 可读性强:
Season.SPRING比0或"spring"更具表达力。 - 编译器检查:如果你写错了枚举值,编译时就会报错,而不是等到运行时才发现。
- 枚举可以有字段和方法(进阶内容),比如可以给每个季节配上气温范围、中文名称等。我们会在面向对象篇深入。
枚举与常量的对比
| 场景 | 使用常量(final) | 使用枚举 |
|---|---|---|
| 表示一组相关的固定值 | 可以,但分散,无类型约束 | 更合适,集中管理,类型安全 |
| 编译器检查 | 不能检查是否在合法范围内 | 可以检查 |
| 适用场景 | 单一不变的值(如 PI) | 一组有限的选择(如状态、类型) |
简单经验:如果只是一两个独立的常量,用 final;如果是有一组固定的选项,用 enum。
4. 一个综合小例子
我们来写一段代码,把字面量、常量和枚举都用上:
package com.example.demo;
/**
* 演示字面量、常量(final)和枚举的用法
*/
public class ConstantsAndEnumsDemo {
// 类常量:用 static final 修饰,全部大写
public static final double TAX_RATE = 0.06; // 税率 6%
public static final int MAX_STUDENTS_PER_CLASS = 50;
// 定义一个枚举:订单状态
public enum OrderStatus {
PENDING, // 待支付
PAID, // 已支付
SHIPPED, // 已发货
DELIVERED, // 已送达
CANCELLED // 已取消
}
public static void main(String[] args) {
// ---- 字面量示例 ----
int price = 199; // 整数字面量
double discount = 0.8; // 浮点数字面量
String productName = "Java编程思想"; // 字符串字面量
boolean inStock = true; // 布尔字面量
// ---- 使用常量 ----
double tax = price * TAX_RATE; // 使用类常量
System.out.println("商品:" + productName);
System.out.println("原价:" + price);
System.out.println("税率:" + TAX_RATE);
System.out.println("税费:" + tax);
// ---- 使用枚举 ----
OrderStatus status = OrderStatus.PAID; // 只能取枚举中定义的值
System.out.println("订单状态:" + status);
// 枚举可以用在 switch 中(我们下篇会详细学)
switch (status) {
case PENDING:
System.out.println("请尽快支付");
break;
case PAID:
System.out.println("已支付,等待发货");
break;
case SHIPPED:
System.out.println("已发货,请注意查收");
break;
case DELIVERED:
System.out.println("已送达,感谢购买");
break;
case CANCELLED:
System.out.println("订单已取消");
break;
default:
System.out.println("未知状态");
}
// ---- 枚举的常用方法 ----
// 枚举自带 values() 方法,返回所有枚举值的数组
System.out.println("所有订单状态:");
for (OrderStatus s : OrderStatus.values()) {
System.out.println(" - " + s);
}
// 枚举的 valueOf() 方法:根据字符串获取枚举值
OrderStatus parsed = OrderStatus.valueOf("SHIPPED");
System.out.println("解析出来的状态:" + parsed);
}
}运行它,你会看到输出涵盖了字面量、常量以及枚举的各种用法。
5. 一些小细节和提醒
- 字符串字面量的不可变性:
String是不可变类,每次对字符串的修改都会创建新对象。这我们以后会详细讲。 - 枚举是类:枚举实际上是一个类,所以它可以有构造方法、字段和方法。比如你可以给
OrderStatus添加一个中文描述字段,这样更实用。我们会在面向对象篇深入。
今天的总结
今天我们学习了三个层次的概念:
- 字面量:代码中直接写出来的数据值,是"原料"。
- 常量(
final):一旦赋值就不能改变的变量,用大写命名,让代码更安全、更易维护。 - 枚举(
enum):一种特殊的类,用来表示一组固定的、有限的值集合,提供了类型安全和更好的可读性。
理解它们之间的区别和适用场景,能让你写出更清晰、更健壮的代码。
动手试试
- 写一个
final常量DAYS_IN_WEEK = 7,然后在main中尝试修改它,观察编译器的报错信息。 - 定义一个枚举
Weekday,包含MONDAY到SUNDAY七个值。在main中:- 声明一个
Weekday变量,赋值为MONDAY,打印它 - 用
Weekday.values()遍历并打印所有值 - 用
Weekday.valueOf("FRIDAY")获取枚举值并打印
- 声明一个
- (进阶) 搜索了解
String.intern()方法的作用,理解字符串常量池的运作机制。
我们下篇文章将继续往前走,聊一聊运算符——让数据真正"动"起来。加、减、乘、除、比较、逻辑判断……这些都是程序逻辑的基石。
我们下一篇见。
📌 获取本系列示例代码请访问 GitCode。
到此这篇关于Java常量、字面量和枚举的文章就介绍到这了,更多相关java常量、字面量和枚举内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
