【发布时间】:2012-12-22 12:09:31
【问题描述】:
我一直在阅读 Bloch 和 Gafter 的 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 是一个 final 类,S 也必须是 String。因此,运行时检查是 有时需要简单的赋值运算符,从不需要 复合赋值运算符。
❖ 数组组件的保存值和右手边的值 操作数用于执行二元运算(字符串连接) 由复合赋值运算符指示(这必然是 +=)。如果这个操作突然完成,那么赋值表达式 出于同样的原因突然完成并且没有分配发生。
这里的 T 是在编译时确定的左侧操作数的类型,而 S 是选定的数组组件。所以我想我会把我的代码修改成这样:
Object[] x = {new Object()};
String i = "Effective Java!";
x[0] += i;
但即使new Object() 甚至不是远程String,也可以毫无问题地编译和运行这段代码。
为什么会这样?这是否意味着 Java 编译器偏离了 JLS?是否还有可能以某种方式解决最初的难题?
【问题讨论】:
-
您是否尝试过创建一个覆盖
toString的对象以打印到stdout/stderr? -
你确定哪个应该编译?或者这本书有错别字。例如,如果 x 和 i 是字节,则
x += i;有效,但x = x + i;无效。 -
您确定您实际测试的是
x += i而不是i += x?我的意思是 (String) += (Object) 将很容易编译,而 (Object) += (String) 将无法编译。 -
@Tinctorius 你不必创建一个对象来打印到标准输出,结果是一个看起来像这样的字符串:
java.lang.Object@5a4b4b50Effective Java!。所以串联很顺利。 -
@Malcolm:我只是打算将其用于(惰性)调试,以了解 Java 实际在做什么。
标签: java expression concatenation variable-assignment