13

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から逸脱していることを意味しますか?そして、どういうわけか元のパズルを解くことはまだ可能ですか?

4

3 に答える 3

4

javac < 1.4.2 で試してみてください。そこでも動作します。

これは、異なるリリース間の変更です。1.4.2 の変更 (x += i; 以前は許可されていましたが、それ以降は許可されていません):
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4642850

JLS 2. エディションでは次のように定義されているため、どちらが正しいですか。

すべての複合代入演算子では、両方のオペランドがプリミティブ型である必要がありますが、+= を除き、左側のオペランドが String 型の場合に右側のオペランドを任意の型にすることができます。

7 の変更 (x += i; 以前は許可されていませんが、以降は許可されています):
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4741726

JLS 3以降はどちらが正しいですか。エディション(http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26を参照してください。以前の前提条件は削除されています)


ちょっとした編集:Java 7.0_10でパズルを修正/解決する方法がわかりません

于 2013-01-08T17:06:46.490 に答える
2

私は以下を持っています、そしてそれは正解として与えられた解決策を示しています:

public class testIt
{
  public static void main(String args[])
  {
    new testIt();
  }

  public testIt()
  {
    Object x = "Buy";
    String i = "Effective Java!"

    x += i;

    x = x + i;
  }
}

これをコンパイルすると、

testIt.java:  incompatible types
found:     java.lang.Object
required:  java.lang.String;

  x += i;
  ^
1 error
于 2013-01-08T15:40:50.473 に答える
0

Java 6では、次のように言うことができます

Object x = 1;
String i = "i";
x = x + i; // compiles
x += i; // doesn't compile in Java 6, but does in Java 7.
System.out.println(x);

なぜこうなった?

と同じ

x[0] = x[0] + i;

Java 7 でコンパイル

Object[] x = {new Object()};
String i = "Effective Java!";
x[0] +=  i;
System.out.println(x[0]);

版画

java.lang.Object@a62b39fEffective Java!

ただし、Java 6 update 37 ではありません

    Error:Error:line (25)java: src\Main.java:25: incompatible types
found   : java.lang.Object
required: java.lang.String

これは、Java コンパイラが JLS から逸脱していることを意味しますか?

Java 6 が現在の JLS に従っていないことを意味していると思われます。準拠していた古いバージョンが存在する可能性があります。

そして、どうにかして元のパズルを解くことはまだ可能ですか?

ヒントがあります。これはコンパイルします

char ch = '0';
ch *= 1.1;

これはしません

char ch = '0';
ch = ch * 1.1;
于 2013-01-08T15:39:39.680 に答える