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