是否可以为程序中其他任何地方的最终变量赋值?还是必须在创建时为它们分配一个值?
class TestClass() {
//this won't compile but is it possible to assign str a value anywhere else in the program?
public static final String str;
}
是否可以为程序中其他任何地方的最终变量赋值?还是必须在创建时为它们分配一个值?
class TestClass() {
//this won't compile but is it possible to assign str a value anywhere else in the program?
public static final String str;
}
您需要在声明时分配一个值 - 如果它不是静态的,则在构造函数中分配,如果是,则在静态初始化块中。一旦设置了值,就无法修改。
像这样做:
public class FinalTest {
private static final String CONSTANT;
private final String value;
static {
CONSTANT = "Hello";
}
public static void main(String [] args) {
FinalTest ft = ((args.length > 0) ? new FinalTest(args[0]) : new FinalTest(CONSTANT));
System.out.println(ft);
}
public FinalTest(String value) {
this.value = value;
}
public String toString() { return this.value; }
}
一个final
变量在被访问之前需要被赋值一次。这意味着如果它从未被赋值并且从未被访问过,编译器不会抱怨。
void foo() {
final int a; // Never assigned, but never accessed either, so no problem
final int b = 7;
System.out.println("b is " + b);
// System.out.println("a is " + a);
// Uncommenting the above line would cause a compile error
}
类似的逻辑适用于final
静态字段,除了假定它们将在某个时间点被访问,因此它们必须在定义行或静态初始化块中进行初始化。
以下是Java 教程中关于静态初始化块的内容:
当初始化值可用并且初始化可以放在一行时,这很有效。但是,这种形式的初始化由于其简单性而具有局限性。如果初始化需要一些逻辑(例如,错误处理或填充复杂数组的 for 循环),简单的赋值是不够的。实例变量可以在构造函数中初始化,其中可以使用错误处理或其他逻辑。为了为类变量提供相同的功能,Java 编程语言包括静态初始化块。
注意:没有必要在类定义的开头声明字段,尽管这是最常见的做法。只需要在使用它们之前声明和初始化它们。
当我们这样做时,一个final
实例(非静态)字段必须在实例初始化完成时被赋值一次。这意味着您可以在三个地方初始化一个(但您必须选择一个):
// For when you know the answer
class Foo {
final int theAnswer = 42;
}
// For when you need to have the answer passed in
class Foo {
final int theAnswer;
Foo(int answer) {
theAnswer = answer;
}
}
// Or for when you need to do some computation
class Bar {
static final int ANSWER_COUNT = 10;
final int[] answers;
Foo() {
answers = new int[ANSWER_COUNT];
for (int i = 0; i < ANSWER_COUNT; i++) {
answers[i] = i;
}
}
// For when you need to do some computation and have many constructors
class Bar {
static final int ANSWER_COUNT = 10;
final int[] answers;
{
answers = new int[ANSWER_COUNT];
for (int i = 0; i < ANSWER_COUNT; i++) {
answers[i] = i;
}
}
// I have many constructors and don't want to copy-paste
// the initialization logic above to all of them
Bar() { ... }
Bar(int i) { ... }
Bar(String blah) { ... }
}
在教程的同一页面中,关于初始化块:
Java 编译器将初始化程序块复制到每个构造函数中。因此,这种方法可用于在多个构造函数之间共享代码块。
在您发布的代码中,该字段static
可以从静态初始化块中获得一个值:
static {
str = "my string";
}
对于非static
字段,它们可以在构造函数中初始化,也可以在实例初始化块中初始化:
class TestClass {
private final String str;
{
str = "my string";
}
TestClass() {
}
}