1. 概述
简单来说,static final
变量,也称为常量,是 Java 中创建初始化后不会改变的类变量的关键特性。 但在涉及 static final
对象引用的情况下,对象的状态可能会变化。
在这个教程中,我们将学习如何声明和初始化常量变量,并讨论它们的用途。
2. static final
变量
static
关键字将一个变量关联到类本身,而不是类的实例。
此外,final
关键字使变量变得不可变,初始化后其值不能更改。
这两个关键字的结合有助于创建常量。它们通常使用大写字母和下划线分隔单词命名。
2.1. 初始化 static final
变量
下面是如何声明和初始化 static final
字段的例子:
class Bike {
public static final int TIRE = 2;
}
在这里,我们创建了一个名为 Bike
的类,有一个名为 TIRE
的常量类变量并将其初始化为2。
另一种方式是通过 static
初始化块来初始化变量:
public static final int PEDAL;
static {
PEDAL = 5;
}
这段代码编译没有错误:
@Test
void givenPedalConstantSetByStaticBlock_whenGetPedal_thenReturnFive() {
assertEquals(5, Bike.PEDAL);
}
对于常量变量,有一些关键规则:
- 必须在声明时或在
static
初始化块中初始化 - 初始化后不能重新赋值
尝试在初始化范围之外初始化它会导致异常。
此外,我们不能通过构造函数初始化它,因为构造函数在创建类的实例时被调用。静态变量属于类本身,而不是单个实例。
2.2. static final
对象
我们也可以创建 static final
对象引用:
public static final HashMap<String, Integer> PART = new HashMap<>();
由于 PART
引用是常量,不能重新赋值:
PART = new HashMap<>();
上述代码会抛出异常,因为我们试图将一个新的引用赋给一个不可变的变量。
然而,我们可以修改对象的状态:
@Test
void givenPartConstantObject_whenObjectStateChanged_thenCorrect() {
Bike.PART.put("seat", 1);
assertEquals(1, Bike.PART.get("seat"));
Bike.PART.put("seat", 5);
assertEquals(5, Bike.PART.get("seat"));
}
在这里,尽管最初设置为1,但我们仍然可以改变 seat
的值。尽管 PART
是一个常量引用,但我们仍然可以修改其内容。只有引用本身是不可变的。
值得注意的是,final
关键字仅使基本类型、String
和其他不可变类型常量化。对于对象,它仅使引用常量,但对象的状态可以被改变。
3. 常量为何有用
使用 static final
变量有多个优点。它提供了更好的性能,因为其值在编译时内联,而不是在运行时查找。
此外,将可重用的值声明为常量可以避免重复使用字面量。常量可以根据访问修饰符在代码的任何地方重用。具有 private
访问修饰符的常量只能在类内部使用。
另外,基本类型或 String
类型的 static final
变量是线程安全的。当在多个线程之间共享时,其值保持不变。
最后,给常量值赋予语义名称可以提高代码可读性。同时,它使代码自我说明。例如,java.math
包提供了如 PI
这样的常量:
@Test
void givenMathClass_whenAccessingPiConstant_thenVerifyPiValueIsCorrect() {
assertEquals(3.141592653589793, Math.PI);
}
Math.PI
以可重用的方式封装了数学常量值。
4. 总结
在这篇文章中,我们了解了如何声明和初始化常量变量,并强调了一些用例。
一个 final static
变量定义了一个类级别的常量。然而,即使引用不能改变,static final
对象仍然可能具有可变性。
如往常一样,示例的完整源代码可在 GitHub 上找到。