一、原文地址:
Compile Time Constants in Java – Zoopable
二、原文翻译
在本教程中,我们将会基本了解java编程语言中的编译时常量。这不是编译时常量的详细教程,但是对于大部分人来说足够了。我们将会知道什么是编译时常量,还有它们怎么样特殊。首先,我们来看下编译时常量的一般规则。
- 必须声明为fianl
- 必须是java原始数据类型或者String
- 必须用声明初始化
- 值必须是常量表达式
如果你不了解所有这些规则,不要担心,我们现在来介绍下这些规则。
原始数据类类型或者String的常量是编译时常量。其他类型都不是编译时常量,甚至包装类也不是。必须用声明初始化他们,否则,他们也不是编译时常量。我们举些例子,下面的都是编译时常量。
final int i = 10;
final int j = 20, k = 30;
final String s = "Hello";
final float f = 10.5f;
下面的不是编译时常量
final Integer i = 10; // 不是原始数据类型或者字符串
int j = 10; // 没有声明为final
final int k; // 没有用声明初始化
k = 10;
final int l, m = l = 20; // l和m都不是编译时常量
最后一个例子可能不直观。我们在l,m声明的同一个语句中初始化了它们,但是它们不是编译时常量。编译时常量必须直接用它们的声明初始化,你不能在声明中间使用不同的变量。
编译常量的最后规则就是编译器必须能够推断编译常量的值。所以它们的值可以是包含字面量(java字面量指原始数据类型和String类型的确定值)和其他编译时常量的任何表达式。我们看一下一些编译时常量的有效值。
final int i = 10 * 20; // 只使用字面量
final int j = i; // 使用其他的编译时常量
final int k = i * 20; // 混合使用编译时常量和字面量
如果你在表达式中使用变量赋值给常量,那么编译器将不知道常量的值(普通变量需要在运行时才能确定值,编译阶段无法获取值),所以它不是编译时常量。下面给出的常量不是编译时常量,因为他们的值不是常量表达式。
int i = 10;
final int j = i; // 使用了变量
final int k = Math.round(10.2); // 方法调用
Java编译时常量!它们有什么特别?
现在我们知道了编译时常量是什么了。我们将要看下为什么它们这么特别。顾名思义,编译时常量得到了编译器的特殊对待。第一个特殊对待的例子就是隐式向下转型(就像字面量)。如果你将值为10的int变量赋值给short变量,你会得到一个错误,但是如果你将值为10的编译时常量赋值给short变量,将会编译通过。这里是例子:
int a = 10;
short s1 = a; // 错误
final int b = 10;
short s2 = b; // 正确
因为编译器知道编译时常量的值,编译器知道b的值是10,所以编译器知道b的值在short数据类型的范围内。你也可以在switch-casa语句中,将编译时变量当做case值,如下例所示:
final int a = 10;
int b = 10;
switch(b) {
case a:
// 省略一些代码
case 20:
// 省略一些代码
}
但是记住,case值不能是字符串或者浮点数,所以你不能使用float、double或者String数据类型的编译时常量当成case值。
上面我们观察到的两个行为,如隐式向下转型和case标签都是同一个原因。不论你在哪使用编译时常量,编译器都会将其使用替换为真实值。所以如果我们写了这个代码:
final int i = 10;
short j = i;
System.out.println(i);
在编译之后变成:
final int i = 10;
short j = 10;
System.out.println(10);
如你所见,在两处使用i的地方,编译器用值10替换了。这就是为什么它们能被当成case值和隐式向下转型的原因。替换值在一些情况下会产生严重影响。
假设我们有两个类在不同文件中,就像这个:
public class ConstantClass {
public static final int MY_CONST = 10;
}
public class Main {
public static void main(String[] args) {
System.out.println(ConstantClass.MY_CONST);
}
}
现在如果我们编译两个类文件,运行Main类,输出是10。因为MY_CONST是编译时常量,所以编译器在main方法中用值替换。现在我们去改变MY_CONST为20,然后只编译ConstantClass 类。然后运行Main类(不再编译),输出依然是10,即Main类被编译时MY_CONST的值。我们必须得重新编译Main类,才能看到输出MY_CONST的新值。
还有一个编译时常量受到特殊对待的是,可以在非静态内部类中声明静态的编译时常量。你可能知道,非静态内部类不能拥有静态成员。但是你可以为非静态内部类添加静态编译时常量
👉👉👉 自己搭建的租房网站:全网租房助手,m.kuairent.com,每天新增 500+房源