[解決済み] finalは定義が不明確?
質問
まず、パズルです。 次のコードは何を表示するのでしょうか?
public class RecursiveStatic {
public static void main(String[] args) {
System.out.println(scale(5));
}
private static final long X = scale(10);
private static long scale(long value) {
return X * value;
}
}
答えてください。
0
以下、ネタバレあり。
印刷する場合
X
を scale(long) で再定義し
X = scale(10) + 3
,
となります。
X = 0
では
X = 3
.
これは、次のことを意味します。
X
が一時的に
0
に設定し、後で
3
.
これは
final
!
static修飾子とfinal修飾子の組み合わせは、定数を定義する場合にも使用されます。 final修飾子は このフィールドは変更できません .
出典 https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html [強調]。
私の質問です。
これはバグなのでしょうか?
また
final
が定義されていないのでしょうか?
以下、気になるコードです。
X
には2つの異なる値が割り当てられています。
0
と
3
.
に違反すると考えています。
final
.
public class RecursiveStatic {
public static void main(String[] args) {
System.out.println(scale(5));
}
private static final long X = scale(10) + 3;
private static long scale(long value) {
System.out.println("X = " + X);
return X * value;
}
}
この質問は、次の質問と重複している可能性があります。
Java static final フィールド初期化順序
.
私は、この質問は
ではなく
重複している
もう一つの質問は、初期化の順序について述べているのに対して
私の質問は、周期的な初期化についてです。
final
タグを使用します。
もう一つの質問だけでは、なぜ私の質問のコードがエラーにならないのか理解できないでしょう。
これは特にernestoが取得する出力を見れば明らかです。
いつ
a
がタグ付けされている場合
final
を実行すると、次のような出力が得られます。
a=5
a=5
というのは、私の質問の本筋とは関係ありません。どのように
final
はその変数を変更するのですか?
どのように解決するのですか?
非常に興味深い発見です。これを理解するためには、Java言語仕様書を掘り下げる必要がある( JLS ).
その理由は
final
は1つしか許可されません。
割り当て
. ただし、デフォルト値は
割り当て
. 実際には、すべての
このような変数
(クラス変数、インスタンス変数、配列コンポーネント) は、その
デフォルト値
の前に、最初から
アサインメント
. そして、最初の代入で参照が変更されます。
クラス変数とデフォルト値
次の例を見てください。
private static Object x;
public static void main(String[] args) {
System.out.println(x); // Prints 'null'
}
には明示的に値を割り当てていません。
x
を指しているが
null
は、デフォルトの値です。比較すると
§4.12.5
:
変数の初期値
各 クラス変数 インスタンス変数、または配列のコンポーネントは デフォルト値 である場合 作成 ( §15.9 , §15.10.2 )
これは、この例のような種類の変数にのみ当てはまることに注意してください。ローカル変数には当てはまらないので、次の例を参照してください。
public static void main(String[] args) {
Object x;
System.out.println(x);
// Compile-time error:
// variable x might not have been initialized
}
同じJLSの段落から。
A ローカル変数 ( §14.4 , §14.14 ) である必要があります。 明示的に値を指定する を使用する前に、初期化 ( §14.4 ) または代入 ( §15.26 ),確定代入の規則を用いて検証可能な方法( §16 (確定代入) ).
最終変数
では、次に
final
からの
§4.12.4
:
最終 変数
変数は、以下のように宣言することができます。 最終 . A 最終 変数は 一度だけ割り当てられる . を指定した場合、コンパイルエラーとなります。 最終 変数に代入された場合、その変数が 割り当ての直前に確実に未割り当てであること ( §16 (確定アサインメント) ).
説明
さて、先ほどの例に戻って、少し修正します。
public static void main(String[] args) {
System.out.println("After: " + X);
}
private static final long X = assign();
private static long assign() {
// Access the value before first assignment
System.out.println("Before: " + X);
return X + 1;
}
を出力します。
Before: 0
After: 1
今まで学んだことを思い出してください。メソッドの内部で
assign
は、変数
X
は
割り当てられていない
にはまだ値がありません。従って、そのデフォルト値を指します。
クラス変数
JLSによれば、これらの変数は常に即座にデフォルト値を指すようになっています(ローカル変数とは対照的)。この後
assign
メソッドは、変数
X
に値が代入されます。
1
であり、そのため
final
は、もう変更できません。ですから、以下のようにすると
final
:
private static long assign() {
// Assign X
X = 1;
// Second assign after method will crash
return X + 1;
}
JLSでの例
Andrewのおかげで、まさにこのシナリオをカバーするJLSの段落を見つけました、それはまたそれを実証しています。
しかし、その前に
private static final long X = X + 1;
// Compile-time error:
// self-reference in initializer
メソッドからのアクセスは許可されるのに、なぜこれは許可されないのでしょうか?以下を見てみましょう。 §8.3.3 は、フィールドがまだ初期化されていない場合、フィールドへのアクセスが制限される場合について述べています。
クラス変数に関連するいくつかのルールが記載されています。
クラス変数への単純な名前による参照の場合
f
クラスまたはインターフェイスで宣言されたC
であれば、それは の場合、コンパイル時にエラーが発生します。 :
シンプルに、その
X = X + 1
はそのルールに引っかかるが、メソッドのアクセスは引っかからない。このシナリオをリストアップし、例も挙げています。
メソッドによるアクセスは、このようにチェックされませんので。
class Z { static int peek() { return j; } static int i = peek(); static int j = 1; } class Test { public static void main(String[] args) { System.out.println(Z.i); } }
は出力を生成します。
0
の変数イニシャライザが
i
の値にアクセスするためにクラスメソッド peek を使用します。j
以前j
は変数イニシャライザーによって初期化され、その時点では はまだデフォルト値である ( §4.12.5 ).
関連
-
スタイルが読み込まれず、ブラウザのコンソールでエラーが報告される。リソースはスタイルシートとして解釈されますが、MIMEタイプtext/htmlで転送されます。
-
が 'X-Frame-Options' を 'deny' に設定しているため、フレーム内にある。
-
javaでよく使われる英単語
-
[解決済み] Javaにおける "final class "の意味とは?
-
[解決済み] Javaの "final "キーワードはどのように機能するのでしょうか?(オブジェクトを修正することは可能です。)
-
[解決済み] Javaリフレクションを用いた静的なプライベートfinalフィールドの変更
-
[解決済み] Java 8のインターフェイスメソッドで "final "が使えないのはなぜですか?
-
[解決済み】finalとeffectly finalの違いについて
-
[解決済み】Javaでfinalキーワードを使用するとパフォーマンスが向上しますか?
-
[解決済み] Java enumとpublic static finalフィールドを持つクラスとでは、どのような利点がありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
エラー java.util.NoSuchElementException
-
IllegalArgumentException この例外を解決する方法
-
スキャナは、タイプに解決することはできません最もルーキー初心者の質問
-
コンストラクタの呼び出しは、コンストラクタのエラー理解の最初のステートメントである必要があります。
-
eclipse の実行時に java 仮想マシンが見つからなかった
-
Methodのinvokeメソッド実装のJavaリフレクション
-
xxx:jarのアーティファクトディスクリプタの読み込みに失敗した問題は解決しました。
-
spring-boot 401 このリソースにアクセスするには完全な認証が必要です エラー解決
-
Exception: java.util.NoSuchElementException: 行が見つかりません
-
このラインで複数のマーカーを解決する方法