プログラムの他の場所にある最終変数に値を代入することは可能ですか? それとも、作成時に値を割り当てることが必須ですか?
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
変数にアクセスする前に、変数に値を1回だけ割り当てる必要があります。これは、値が割り当てられたりアクセスされたりしたことがない場合、コンパイラは文句を言わないことを意味します。
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チュートリアルでは、静的初期化ブロックについて次のように述べています。
これは、初期化値が使用可能であり、初期化を1行に配置できる場合にうまく機能します。ただし、この形式の初期化には、その単純さのために制限があります。初期化に何らかのロジック(たとえば、エラー処理や複雑な配列を埋めるためのforループ)が必要な場合、単純な割り当てでは不十分です。インスタンス変数はコンストラクターで初期化でき、エラー処理またはその他のロジックを使用できます。クラス変数に同じ機能を提供するために、Javaプログラミング言語には静的初期化ブロックが含まれています。
注:これは最も一般的な方法ですが、クラス定義の最初にフィールドを宣言する必要はありません。それらを使用する前に、それらを宣言して初期化する必要があるだけです。
その間、final
インスタンス(非静的)フィールドには、インスタンスの初期化が完了するまでに1回だけ値を割り当てる必要があります。これは、1つを初期化できる場所が3つあることを意味します(ただし、1つを選択する必要があります)。
// 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() {
}
}