Я читал Java Puzzlers Блоха и Гафтера и добрался до головоломки 10 (Tweedledee). Суть этой головоломки в том, чтобы
предоставьте объявления для переменных
x
иi
таким образом, чтобы это было допустимым утверждением:x = x + i;
но это не так:
x += i;
Решение этого выглядит, согласно книге, так:
Object x = "Buy ";
String i = "Effective Java!";
В книге утверждается, что в операторе +=
правое выражение может быть любого типа, только если левое выражение имеет тип String
. Однако я попытался запустить этот код, и он скомпилировался и запустился без проблем.
Затем я углубился в спецификацию языка Java. В разделе 15.26.2 говорится о двух случаях: когда левое выражение является выражением доступа к массиву, а когда нет. Если выражение левого операнда не является выражением доступа к массиву, то JLS ничего не говорит о том, что левое выражение является строкой. Когда это так, эта часть применяется:
Если T является ссылочным типом, то он должен быть String. Поскольку класс String является конечным классом, S также должен быть String. Поэтому проверка во время выполнения, которая иногда требуется для простого оператора присваивания, никогда не требуется для составного оператора присваивания.
❖ Сохраненное значение компонента массива и значение правого операнда используются для выполнения бинарной операции (конкатенации строк), указанной составным оператором присваивания (обязательно +=). Если эта операция завершается внезапно, выражение присваивания завершается внезапно по той же причине, и присваивание не происходит.
T — это тип левого операнда, определенный во время компиляции, а S — выбранный компонент массива. Поэтому я подумал, что изменю свой код на это:
Object[] x = {new Object()};
String i = "Effective Java!";
x[0] += i;
Но даже этот код компилируется и работает без проблем, хотя new Object()
даже отдаленно не является String
.
Почему это происходит? Означает ли это, что компилятор Java отличается от JLS? И можно ли еще как-то решить изначальную головоломку?
toString
для печати в stdout/stderr? - person   schedule 08.01.2013x += i;
допустимо, аx = x + i;
— нет. - person Patricia Shanahan   schedule 08.01.2013x += i
, а неi += x
? Я имею в виду, что (String) += (Object) будет легко компилироваться, когда (Object) += (String) не будет компилироваться. - person Dmitry Zaytsev   schedule 08.01.2013java.lang.Object@5a4b4b50Effective Java!
. Таким образом, конкатенация происходит красиво. - person Malcolm   schedule 08.01.2013