JLS和Sun javac之间的对应关系是什么/为什么它们不匹配

4
在Java中,假设有以下代码:
String a = "str";
CharSequence b = "charseq";

你可以编写代码。
b = b + a;

但是不能编写(会产生编译器错误)。

b += a;

错误信息为:
incompatible types
found   : java.lang.CharSequence
required: java.lang.String

现在在JLS第二版中,可以通过15.26.2 复合赋值运算符中的这一行来解释:
所有复合赋值运算符都要求两个操作数都是原始类型,除了+=,如果左操作数为String类型,则允许右操作数为任何类型。
但是在JLS第三版中,这条注释消失了,关于复合运算符唯一需要注意的事项在15.26.2 复合赋值运算符中提到:
形式为E1 op=E2的复合赋值表达式等价于E1=(T)((E1)op(E2)),其中T是E1的类型,只不过E1只被计算一次。
看起来这并不起作用(请参见上文)。
因此我的问题是 - javac和JLS之间的关系究竟是什么,这个特定的例子是javac中的错误还是JLS中的错误?

1
本质上,你已经回答了自己的问题:“所有复合赋值运算符都要求两个操作数都是原始类型,除了+=运算符允许右操作数为任何类型,如果左操作数为String类型。”请注意,您的左操作数并不是String类型。 - KevinDTimm
1
是的,但他在JLSv3中指出该注释已更改,现在执行了一个转换。尽管它被声明为CharSequence,但实际实现是一个字符串,因此如果JLSv3中的注释是正确的,它应该进行强制转换并正常工作。 - Simone Gianni
看起来你正在测试的 javac 符合 JLSv2 而不是 JLSv3。 - DwB
2 DwB - 对的,这就是我提出这个问题的原因 - javac和JLS之间的关系是什么。似乎jdk6中的javac应该符合JLSv3,但显然它并没有。 - atamur
看起来编译器在这里有一个错误——他们的开发人员没有看到规范在这里发生了变化。(顺便说一下,用 Object 代替 CharSequence 应该也会发生同样的情况。) - Paŭlo Ebermann
3个回答

4

编译器错误是您的javac版本中的错误。如先前答案中指出,此错误已在Java 7中修复。

请参见Sun bug数据库中的Bug ID 7058838等示例:

  • description:

    A following function cannot be compiled in java 1.6 or less,. but it can be compiled in java 1.7.

    public static void main(String[] args) {
           Object x = "x";
           String y = "y";
           x += i;
    }
    
  • state:
    Not a Defect
  • evaluation:

    For an Object x and a String y, x+=y is just x=(Object)(x+y). Since y is a String, x undergoes string conversion to produce a string which is concatenated with y, before the no-op cast to Object. The JLS has not changed in this area between SE 6 and SE 7; the program should have been legal for many years.


背景请参见旧的错误编号4741726

  • 描述:

    javac曾允许表达式形式为o += s,其中o是类型为Object的变量,s是类型为String的表达式。我们最近修复了这个问题(4642850),但这导致了构建失败(4741702)。也许这种情况很普遍,我们应该放宽规范而不是修复编译器?

  • 类别:
    java:compiler
  • 修复版本:
    7(b25) - 据我所知,这意味着在Java 7的第25版中已经修复了此问题
  • 评估:

    我倾向于放宽规范,但在做出最终决定之前,我们必须知道其他实现的情况。
    2002-09-04
    JLS3允许Object+=String,因为'+'表示字符串连接,这能够像将String与Object连接一样轻松地将Object与String连接起来。
    2008-01-31


感谢您在这里查找错误ID(我找不到它们)。 - Paŭlo Ebermann
1
@PaŭloEbermann 是的,在这种情况下,JLS部分ID是关键。我谷歌搜索了site:bugs.sun.com "15.26.2"。出现的问题可能不是最相关的,但通过浏览Related Bugs链接,最终找到7058838和4741726。 - gnat

2
应该是javac的bug。在javac 7中编译没有问题,所以有人报告了这个问题并进行了修复。

+1 为了测试这个。 (尽管有没有正在进行的JLS重写,即我们会很快得到JLS 4?) - Paŭlo Ebermann

0
实际上,你已经回答了自己的问题:
所有复合赋值运算符都要求两个操作数都是原始类型,除了 += 运算符,如果左操作数是 String 类型,则允许右操作数为任何类型。
请注意,你的左操作数不是 String 类型。

那个评论来自JLSv2,而javac从java 6开始似乎是基于JLSv3构建的,因此有这个问题。 - atamur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接