たくさんのスペックを読んで考えた後、私は次のように結論付けました。
Java5またはJava6コンパイラでは、これは正しい動作です。第16章「 Java言語仕様の明確な割り当て、第3版は次のように述べています。
各ローカル変数(§14.4)およびすべての空白final
(§4.12.4)フィールド(§8.3.1.2)には、その値へのアクセスが発生したときに、確実に割り当てられた値が必要です。その値へのアクセスは、単純代入演算子の左側のオペランドを除いて、式の任意の場所にある変数の単純な名前で=
構成されます。
(私の強調)。したがって、式では、インスタンス変数の単純な名前ではないため2 * this.x
、このthis.x
部分は「[ 's]値へのアクセス」とは見なされません(したがって、明確な割り当ての規則の対象にはなりません) 。(注:明確な割り当てが発生する場合のルールは、上記のテキストの後の段落で、のようなものを許可し、その後は確実に割り当てられると見なされます。カウントされないのはアクセスのルールのみです。)値に注意してください。この場合のofは、 §17.5.2に従ってゼロになります。x
this.x
x
this.x = 3
x
this.x
this.x
Java 7コンパイラでは、これはコンパイラのバグですが、理解できるバグです。Java言語仕様の第16章「明確な割り当て」、Java 7SEEditionは次のように述べています。
各ローカル変数(§14.4)とすべての空白final
フィールド(§4.12.4、§8.3.1.2)には、その値へのアクセスが発生したときに、確実に割り当てられた値が必要です。
その値へのアクセスは、単純代入演算子(§15.26 )の左側のオペランドを除いて、式の任意の場所にある変数の単純な名前(または、フィールドの場合は、で修飾されたフィールドの単純な名前)で構成されます。 this
1)。=
(私の強調)。したがって、式2 * this.x
では、そのthis.x
部分は「[ 's]値へのアクセス」と見なされ、コンパイルエラーが発生するはずです。x
しかし、最初のものをコンパイルする必要があるかどうかを尋ねたのではなく、なぜコンパイルするのか(一部のコンパイラーでは)を尋ねました。これは必然的に推測ですが、2つの推測をします。
- ほとんどのJava7コンパイラは、Java6コンパイラを変更して作成されています。一部のコンパイラ作成者は、この変更に気付いていない可能性があります。さらに、多くのJava-7コンパイラとIDEは依然としてJava 6をサポートしており、一部のコンパイラ作成者は、Java-6モードで受け入れるJava-7モードで何かを具体的に拒否する意欲を感じていない可能性があります。
- 新しいJava7の動作は、奇妙なことに一貫性がありません。のようなもの
(false ? null : this).x
はまだ許可されており、さらに言えば、(this).x
それでも許可されています。この変更の影響を受けるのは、特定のトークンシーケンスthis
と.
フィールド名だけです。確かに、そのような矛盾は代入ステートメントの左側にすでに存在していましたが(書くことはできますthis.x = 3
が、できません(this).x = 3
)、それはより簡単に理解できます。this.x = 3
それ以外の場合は禁止されている構造の特別に許可されたケースとして受け入れられobj.x = 3
ます。それを許可するのは理にかなっています。2 * this.x
しかし、他の方法で許可された建設の特別な禁止されたケースとして拒否することは意味がないと思います2 * obj.x
、(1)この特別な禁止ケースは括弧を追加することで簡単に回避でき、(2)この特別な禁止ケースは以前のバージョンの言語で許可されていました。また、(3)final
フィールドにのような場合と、のような場合の両方のために、初期化されるまでのデフォルト値(たとえば0
、の場合)は、にアクセスするメソッドです。したがって、一部のコンパイラ作成者は、この一貫性のない変更を行う意欲を感じていない可能性があります。int
(this).x
this.foo()
foo()
x
これらのいずれかは驚くべきことです—コンパイラー作成者は仕様に対するすべての変更について詳細な情報を持っていたと思います。私の経験では、Javaコンパイラーは通常、仕様に正確に準拠するのに非常に優れています(すべてのコンパイラーが仕様を持っている一部の言語とは異なります)。独自の方言)—しかし、まあ、何かが起こった、そして上記は私の唯一の2つの推測です。