我一直在阅读 Bloch 和 Gafter 的 Java Puzzlers 并进入了谜题 10 (Tweedledee)。这个谜题的本质是
为变量提供声明,
x
这样i
这是一个合法的声明:x = x + i;
但这不是:
x += i;
根据这本书,解决方案看起来像这样:
Object x = "Buy ";
String i = "Effective Java!";
该书声称,在+=
运算符中,只有当左侧表达式具有 type 时,右侧表达式才可以是任何类型String
。但是,我尝试运行此代码,它编译并运行没有任何问题。
然后我深入研究了 Java 语言规范。第 15.26.2 节讨论了两种情况:左侧表达式是数组访问表达式时,以及不是。如果左侧操作数表达式不是数组访问表达式,则 JLS 不会说明左侧表达式是字符串。如果是,这部分适用:
如果 T 是引用类型,那么它必须是 String。因为 String 类是 final 类,所以 S 也必须是 String。因此,对于复合赋值运算符,从不需要简单赋值运算符有时需要的运行时检查。
❖ 数组组件的保存值和右手操作数的值用于执行复合赋值运算符(必须是+=)指示的二元运算(字符串连接)。如果此操作突然完成,则赋值表达式出于同样的原因突然完成并且不发生赋值。
这里的 T 是在编译时确定的左侧操作数的类型,S 是选定的数组组件。所以我想我会把我的代码修改成这样:
Object[] x = {new Object()};
String i = "Effective Java!";
x[0] += i;
但是即使这段代码编译和运行也没有任何问题,即使它甚至new Object()
不是远程的String
.
为什么会这样?这是否意味着 Java 编译器偏离了 JLS?还有可能以某种方式解决原来的难题吗?