是否可以在程序的其他任何位置为最终变量赋值?或者是否必须在创建时为其分配值?
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;
}
答案 0 :(得分:3)
如果值已经声明,则需要在构造函数中指定一个值(如果它不是静态的),如果是,则在静态初始化程序块中。设置值后,无法修改。
这样做:
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; }
}
答案 1 :(得分:2)
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
静态字段,除非它假设它们将在某个时刻被访问,因此必须在定义行或在静态初始化程序块中。
这里有the Java tutorial关于静态初始化块的说法:
当初始化值可用且初始化可以放在一行时,这很有效。然而,这种形式的初始化由于其简单性而具有局限性。如果初始化需要一些逻辑(例如,错误处理或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) { ... }
}
从the same page in the tutorial开始,关于初始化程序块:
Java编译器将初始化程序块复制到每个构造函数中。因此,这种方法可用于在多个构造函数之间共享代码块。
答案 2 :(得分:1)
在您发布的代码中,字段为static
,因此可以从静态初始化块中获取值:
static {
str = "my string";
}
对于非static
字段,它们可以在构造函数中初始化,也可以在实例初始化程序块中初始化:
class TestClass {
private final String str;
{
str = "my string";
}
TestClass() {
}
}