【问题标题】:How can the same expression be evaluated differently?如何以不同的方式评估相同的表达式?
【发布时间】:2012-05-08 19:09:37
【问题描述】:

谁能解释一下这个病态的巫术:

    System.out.println(("a".equals("a")));  //true
    System.out.println(("a".equals("а")));  //false

    System.out.println(("Joachim Garraud" == "Joachim Garraud"));       //true
    System.out.println(("Joachim Garraud" == "Joаchim Garraud"));       //false
    System.out.println(("Joachim Garraud".equals("Joаchim Garraud")));  //false
    System.out.println(("Joachim Garraud".equals("Joachim Garraud")));  //true

我不知道这里发生了什么,但我发誓我得到了这些结果。我真的看不出有什么区别,而且结果是一致的 - 当我复制“假行”时,我再次得到假,反之亦然。

【问题讨论】:

  • 尝试再次运行它,看看你得到了什么。他们都应该是true
  • 如果这不只是您在欺骗我们,请提供一些有关使用的 JVM 的信息。还可以尝试使用 UTF-8 之类的 unicode 编码将字符串转换为字节数组,然后比较这些数组。
  • 对不起,你的结果根本不可能。
  • @Stephen,我愿意回溯我的答案,但"a".equals("a") 怎么可能是假的?
  • @WATTOStudios - 我的回答给出了一种可能的解释。

标签: java string boolean equals


【解决方案1】:

我怀疑原因是您的代码包含不同版本的(例如)"a" 字符。例如,小写 LATIN A 可能看起来与小写 CYRILIC A 相同......但它们是不同的 Unicode 代码点(\u0061\u0430),因此不相等。

【讨论】:

  • 看起来就是这样,您可以查看我对@Old Pro 的回答的评论,以查看我使用getBytes() 获得的字节数。谢谢。我会选择你的答案作为接受的答案,因为那一定是发生的事情(尽管我仍然很困惑,因为我自己输入了 a 的)。不过,我希望我也可以感谢@Thomas 和@Old Pro,他们用字节数组技巧解决了这个问题。
【解决方案2】:

在打印出字符串的二进制代码后(正如 Thomas 和 Old Pro 所建议的那样),最终发现 BOM 是导致不等式的原因:

for( byte b : "a".getBytes() ) { // The first "a" copied from the false-expression
    System.out.printf("%x ", b);
}
for( byte b : "a".getBytes() ) { // The second "a" copied from the false-expression
    System.out.printf("%x ", b);
}

// Again, copied from the false-evaluating expression:
for( byte b : "Joachim Garraud".getBytes() ) {
    System.out.printf("%x ", b);
}
for( byte b : "Joachim Garraud".getBytes() ) {
    System.out.printf("%x ", b);
}

...导致以下输出:(打印输出对齐以提高可读性)

ef bb bf 61
         61

ef bb bf 4a 6f 61 63 68 69 6d 20 47 61 72 72 61 75 64 
         4a 6f 61 63 68 69 6d 20 47 61 72 72 61 75 64

现在我可以用 Joachim Garraud 理解这一点,因为我从两个不同的 .txt 文件中获得了这两个“两个”——第一个在第一个文件的开头,第二个在第二个文件的中间。 然而,我自己输入了 a,但我不记得我到底是怎么做到的了——也许我复制粘贴了一段带有错误的代码——评估表达式,然后删除引号内的 Joachim Garraud 并键入 a,这并没有删除 BOM。

无论如何,我希望可以从中学到一些东西。此外,这家伙在这里免费获得了很多免费广告(实际上是为了 BOM),尽管我认为他是某种新的 Chuck Norris。不是粉丝什么的。

【讨论】:

  • 是的......你应该使用“Jon Skeet”。他是 SO 的官方 Chuck Norris :-)
【解决方案3】:

我也不知道发生了什么,因为当我复制你所有的代码时,每行打印true

所以把它全部复制回你的机器,一切都应该被修复。

如果我不得不猜测的话,我会猜测其中一个“a”字符有一个变音符号,您的显示字体将其映射到一个没有该标记的字符中。

下次打印出十六进制字符串的二进制代码并比较它们。

【讨论】:

  • 我猜是这样:System.out.println(("a".getBytes())); // [B@18fe7c3 System.out.println(("a".getBytes())); // [B@b8df17 System.out.println(("Joachim Garraud".getBytes())); // [B@13e8d89 System.out.println(("Joachim Garraud".getBytes())); // [B@1be2d65 但奇怪的是输入了“a”。“Joachim”来自文件,但我输入了“a”是我自己去检查这种疯狂......它把我逼疯了。无论如何,感谢您提供字节检查提示。
  • 这有点帮助,但不多。你所做的只是表明它们是不同的对象。您没有打印出字节数组的内容。
  • 哦,对了。为什么我觉得……哦,好吧。感谢您指出这一点,现在我已经真正将它们打印出来了,我明白那里发生了什么。现在写答案。
【解决方案4】:

您还应该寻找不可显示的字符。

System.out.println("<\ufff9\ufffa\ufffb>");
System.out.println("<>");
System.out.println("<>".length());
System.out.println(Arrays.toString("<>".toCharArray()));

看起来像这样

<>
<>
5
[<, , , , >]

将其复制到您的 IDE 中,这些字符将不会出现,但它们就在那里。 ;)

【讨论】:

  • BOM 导致了问题(我的答案中有更多信息),由于它是一个不可显示的字符,我已将其更新为可接受的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
相关资源
最近更新 更多