BlochとGafterのJavaPuzzlersを読んでいて、パズル10(Tweedledee)にたどり着きました。このパズルの本質は
x
変数の宣言を提供しi
、これが正当なステートメントであるようにします。x = x + i;
しかし、これはそうではありません:
x += i;
この本によると、これに対する解決策は次のようになります。
Object x = "Buy ";
String i = "Effective Java!";
+=
この本は、演算子では、左側の式のタイプが。である場合にのみ、右側の式を任意のタイプにすることができると主張していString
ます。しかし、私はこのコードを実行しようとしましたが、問題なくコンパイルおよび実行されました。
次に、Java言語仕様を掘り下げました。セクション15.26.2では、左側の式が配列アクセス式である場合とそうでない場合の2つのケースについて説明しています。左側のオペランド式が配列アクセス式でない場合、JLSは左側の式が文字列であることについて何も言いません。その場合、この部分は次のように適用されます。
Tが参照型の場合、文字列である必要があります。クラスStringは最終クラスであるため、SもStringである必要があります。したがって、単純代入演算子で時々必要となる実行時チェックは、複合代入演算子では必要ありません。
❖配列コンポーネントの保存された値と右側のオペランドの値は、複合代入演算子(必ず+ =)で示される二項演算(文字列連結)を実行するために使用されます。この操作が突然完了した場合、同じ理由で代入式が突然完了し、代入は発生しません。
ここでのTは、コンパイル時に決定される左側のオペランドのタイプであり、Sは選択された配列コンポーネントです。だから私は自分のコードを次のように変更すると思いました:
Object[] x = {new Object()};
String i = "Effective Java!";
x[0] += i;
new Object()
しかし、このコードでさえ、リモートでさえなくても問題なくコンパイルおよび実行されますString
。
なぜこうなった?これは、JavaコンパイラがJLSから逸脱していることを意味しますか?そして、どういうわけか元のパズルを解くことはまだ可能ですか?