object.equals方法在Java中应该如何工作?

object.equals方法在Java中应该如何工作?,java,Java,这是我的源代码。我正在尝试实现一个简单的程序,它向用户提出一个问题,并期望答案是“是”或“否”,并且只有当用户回答“是”或“否”时才会终止。我建议我不要使用==比较,而是使用equals方法,这样程序就可以理解用户是否输入了“yes”而不是“yes”。但通过这种方式,结果是相同的,该方法似乎比较用户的答案,如果它是“是”或“否”。例如,它不接受“否”的回答。这种方法合乎逻辑吗?这样行吗?如何更改程序以接受“是”“是”“否”“否”等答案。?我将感谢您的帮助:) ==vs.equals()的语义 首

这是我的源代码。我正在尝试实现一个简单的程序,它向用户提出一个问题,并期望答案是“是”或“否”,并且只有当用户回答“是”或“否”时才会终止。我建议我不要使用==比较,而是使用equals方法,这样程序就可以理解用户是否输入了“yes”而不是“yes”。但通过这种方式,结果是相同的,该方法似乎比较用户的答案,如果它是“是”或“否”。例如,它不接受“否”的回答。这种方法合乎逻辑吗?这样行吗?如何更改程序以接受“是”“是”“否”“否”等答案。?我将感谢您的帮助:)

==
vs
.equals()的语义
首先,你误解了语义

=
测试对象标识
A==B
表示is
A
是对与
B
完全相同的对象的引用

.equals()
应用自定义逻辑来测试对象是否以某种逻辑方式相等,而不是完全相同的对象。要正确实现这一点,两个对象也应该具有相同的
.hashCode()

惯用Java解决方案 因为
String
对象是
final
,这意味着它不能从中继承。不能覆盖
字符串
对象上的
.equals()

您需要做的是将输入预处理成可以直接与目标值进行比较的内容,使用
.equalsIgnoreCase()

一种方法是使用,
answer.replaceAll(“\\s”,”)
删除所有空白,然后您可以使用
.equalsIgnoreCase()
将其与目标字符串比较

替换
askYesNoQuestion()
的更好方法是:

private boolean isAnswerYesOrNo(final String answer)
{
    final String input = answer.replaceAll("\\s","");
    return "yes".equalsIgnoreCase(input) || "no".equalsIgnoreCase(input);
}
如果输入参数正好是
null
“yes”,那么将
文本
与输入参数进行比较将使您免受
NullPointerExceptions
的影响。equalsIgnoreCase()
永远不会抛出
NullPointerException`。这就是惯用Java

找一本更好的书
如果那本书真的说了你所说的话,那它就没有多大用处。此外,它还教导您编写大量代码来处理错误的输入,而这是一种完全的反模式,一个设计良好的程序在退出时会详细解释如何修复输入的确切问题。

如果您使用
==
,您将比较两个字符串对象的引用(内存指针)。如果使用
equals
,则将运行
String
类中的自定义方法,该方法将执行一些“智能”比较,在这种情况下,请检查所有字符是否相同,以及整个字符串是否具有相同的长度

如果希望支持大小写混合的字母,可以使用
“someString”.equalsIgnoreCase(“someString”)
(返回true)。这是通过(粗略地说)使两个字符串都小写(所以大小写不重要)并使用equals进行比较来实现的


编辑:其他的海报让我意识到,除了大写,你还想在空格不重要的地方寻找字符串相等。如果是这样的话,一个类似于将所有内容都转换为小写的技巧也适用,首先删除所有空格,正如@LouisWasserman在他的回答中所说的那样

如果需要模糊地确定是/否,首先需要精确的规则来确定匹配的内容。根据你的例子,我可以提出以下建议:

private boolean askYesNoQuestion(String str) {
  str = str.replace(" ", "").toUpperCase();
  return str.equals("YES") || str.equals("NO");
}
如果您对顶级性能感兴趣,而对可理解性则完全不感兴趣,请使用以下选项:

private static final Pattern p = 
    Pattern.compile("y\\s*e\\s*s|n\\s*o", Pattern.CASE_INSENSITIVE);
private boolean askYesNoQuestion(String str) {
  return p != null && p.matcher(str.trim()).matches();
}

根据上面对==和.equals的解释,这里有两个一行程序的示例,可以进行您想要的比较

if ( Pattern.matches("\\s*[yY]\\s*[eE]\\s*[sS]\\s*", input) ) {
  // do something
}


if ( input.replaceAll("\\s", "").equalsIgnoreCase("yes") ) {
  // do something
}

.equals
=
的区别在于它忽略空格或大小写。你或者需要买一本新书,或者只是再读一遍那部分:)唯一有意义的部分是“我建议我不要使用==比较,而是使用equals方法的那本书”-例如,请参见:其余部分没有意义。在Java中,你不能覆盖像
==
这样的运算符,但你可以覆盖
.equals()
方法IIRC。我还相信有一个
.equalsIgnoreCase()
方法。您拥有的代码将只接受
。如果你想接受字母之间的空格等,你必须对其进行编码。assylias发布的链接上的建议答案很好地解释了这一区别。这本书来自斯坦福大学,特别指出:“从用户读取的值很可能是由字符‘y’、‘e’和‘s’组成的对象,但它不会是与程序中出现的常量字符串‘yes’相同的对象。”。相反,您需要问的是两个字符串是否包含相同的字符序列,这正是equals方法所做的。因此,您需要wdte的语句是if(answer.equals(“yes”)…
.toLowerCase()
是多余的,因为
.equalsIgnoresCase()
是更好的选择,特别是考虑到Unicode。与
的匹配也不像
“\\s”
那样全面。而针对
str
而不是文本进行测试将打开
NullPointerExceptions
。这里有很多非惯用Java语言。所以你投票是因为还有一些小地方需要改进??好极了。顺便说一句,equalsIgnoreCase将做两次这项工作,我已经有了它,并明确地使用了这个解决方案。根据“”进行匹配是基于OP的示例,在这种情况下更快。至于NPE,首先看一下你眼中的日志。你自己的解决方案使用了正则表达式,而且很糟糕。至于性能,我已经做了测试:您的解决方案与我的前两个解决方案相差5%以内;我的第二个解决方案至少快了五倍。至于
equalsIgnoreCase
vs
if ( Pattern.matches("\\s*[yY]\\s*[eE]\\s*[sS]\\s*", input) ) {
  // do something
}


if ( input.replaceAll("\\s", "").equalsIgnoreCase("yes") ) {
  // do something
}