当前位置: 首页 > 知识库问答 >
问题:

如何使E1=E2非法,而E1=E1 E2是合法的?

高运诚
2023-03-14

我一直在阅读布洛赫和加夫特的《Java谜题》,并找到了谜题10。这个谜题的本质是

为变量xi提供声明,使其成为法律声明:

x = x + i;

但这不是:

x += i;

根据这本书,解决方案如下:

Object x = "Buy ";
String i = "Effective Java!";

这本书声称,在=操作符中,只有当左手表达式的类型为字符串时,右手表达式才可以是任何类型。然而,我试图运行这段代码,它编译并运行时没有任何问题。

然后我深入研究了Java语言规范。第15.26.2节讨论了两种情况:当左手表达式是数组访问表达式时,当它不是。如果左手操作数表达式不是数组访问表达式,那么JLS没有说左手表达式是字符串。当它是字符串时,这部分适用:

如果T是引用类型,那么它必须是字符串。因为类String是最后一个类,所以S也必须是String。因此,对于简单赋值运算符有时需要的运行时检查,对于复合赋值运算符永远不需要。

❖ 数组组件的保存值和右侧操作数的值用于执行复合赋值运算符(必须为=)指示的二进制操作(字符串串联)。如果此操作突然完成,那么赋值表达式也会因为同样的原因突然完成,并且不会发生赋值。

这里的t是编译时确定的左操作数的类型,S是选定的数组组件。所以我想我应该把我的代码修改成这样:

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

但是,即使new Object()远不是String,这个代码编译和运行也没有任何问题。

为什么会这样?这是否意味着Java编译器偏离了JLS?还有可能以某种方式解决最初的难题吗?


共有3个答案

墨翔宇
2023-03-14

在Java6中,你可以说

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;

用Java7编译

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

指纹

java.lang.Object@a62b39fEffective Java!

但不适用于Java6更新37

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

这是否意味着Java编译器偏离了JLS?

我怀疑这意味着Java6没有遵循当前的JLS。它可能遵守了一个旧版本。

还有可能以某种方式解决最初的难题吗?

有一个暗示。这就是

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

这并不是

char ch = '0';
ch = ch * 1.1;
倪鹏
2023-03-14

我有以下内容,它显示了给定的解决方案作为正确答案:

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
岳枫
2023-03-14

用javac试试

这是不同版本之间的变化。1.4.2(x=i;之前允许,之后不允许)的更改:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4642850

这是正确的,因为JLS 2。版本定义:

所有复合赋值运算符都要求两个操作数都是基元类型,除了=,如果左手操作数是字符串类型,则允许右手操作数为任何类型。

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中的难题

 类似资料:
  • 无法将xml转换为java pojo对象。请查看以下详细信息:- 输入xml- pom.xml有依赖关系:- 公司Java语言 受雇者Java语言 将xml转换为java代码:- 下面的错误我在转换xml到pojo时得到 线程“main”com中出现异常。fasterxml。杰克逊。数据绑定。exc.MismatchedInputException:无法构造com的实例。测验Employee(尽管

  • OrdersController: -getOrders -GetordersforCustomer(int CustomerId) -GetOrderWithCustomerInfo(int CustomerId) CustomerController -GetCustomer(int id) -getCustomerWithinZipCode 因此,使用像这样的API控制器方法并不遵循其他地方

  • 问题内容: 我有2个矩阵,我需要将它们相乘,然后打印每个单元格的结果。准备好一个单元格后,我就需要打印它,但是例如,即使[2] [0]的结果先准备好,我也需要在单元格[2] [0]之前打印[0] [0]单元格。所以我需要按顺序打印它。因此,我的想法是让打印机线程等待,直到通知它准备打印正确的单元格,然后它将打印该单元格并返回等待状态,依此类推。 所以我有这个线程做乘法: 打印每个单元格结果的线程:

  • 我目前正在迭代一个数组,其中每个索引包含两个节点和一个关系(第1部分)- 我读了这篇文章,但我不明白如何实现它,使两个相同的节点具有相同的ID。我现在的代码是这样的: 创建两个节点 创造他们的关系 将关系添加到节点 坚持使用Neo4jTemplate.save() 我需要更改什么以合并而不是创建?我是否需要在持久化之前进行检查,或者在持久化SDN 4时是否有方法进行检查? 编辑: 我决定使用Neo

  • 问题内容: 看起来它将在即将发布的版本中完全淘汰,取而代之的是新的生命周期方法:static getDerivedStateFromProps() 。 经检查,它看起来像你现在无法作出直接比较和,就像你可以在。有没有办法解决? 而且,它现在返回一个对象。我是否正确假设返回值本质上是? 以下是我在网上找到的示例:状态源自props / state 。 之前 后 问题答案: 有关删除的:你应该能够与组