我正在创建一个用户尝试猜测名称的迷你游戏。但是当我想比较两个文本字符串以查看它们是否相同时,它似乎不起作用。
final String miNombre = "Jordi";
Scanner input = new Scanner(System.in);
System.out.println("Adivina mi nombre: ");
while (true) {
String intento = input.next();
if(intento == miNombre) {
System.out.println("Acertaste!");
break;
} else {
System.out.println("Intentalo de nuevo!");
}
}
出口:
Adivina mi nombre:
manuel
Intentalo de nuevo!
jordi
Intentalo de nuevo!
Jordi
Intentalo de nuevo!
Java
只有原始类型(在 JLS (§4.2) 中描述,例如orint
)char
与 进行比较==
,其中的String
s(和其他对象)Java
与方法 进行比较equals
。String#equals(Object)
==
比较类型引用String
,但相等性测试确定两个操作数是否引用同一个对象String
。结果是false
,如果操作数是不同的 String 对象,即使它们包含相同的字符序列。所以你的比较应该是:
出口:
澄清:
我已将变量
miNombre
放在比较的开头以避免NullPointerException
ifintento == null
(是的,与 的比较null
也是用 进行的==
)。作为额外的:如果它
null
是表示中的有效值(因此我们希望避免使用一个NPE
),它Objects.equals
可以从Java 7
并且如果两者都为真null
或false
只有一个为真,则返回true。在这种情况下,您可以使用
String#equalsIgnoreCase(Object)
将忽略MAYUSCULAS
或MINUSCULAS
进行比较时的方法:JLS (§15.21)相等运算符 (
==
and!=
) 可用于比较两个可转换 (§5.1.8) 数值类型的操作数,或两个boolean
or类型的操作数,Boolean
或两个>
类型为引用的操作数,或类型null
。所有其他情况都会导致编译时错误。从 Java 7 开始,可以使用类的方法来比较两个字符串的相等性。那是:
equals
java.util.Objects
因为在使用此路径时,它们可以分别
a.equals(b)
转换b.equals(a)
为java.lang.NullPointerException
if it或it isa
,或者他们可以没有任何风险。null
b
null
a
b
null
如果您使用的是 Java 6(或更低版本),则从此类中的代码
if
中,我们可以重写如下:“==”运算符比较两个引用,也就是说,如果两个对象占用相同的内存位置,则返回true 。
“equals”方法比较对象的值。
这是新开发人员的常见错误。
为了补充其他答案,我将告诉您没有规则来比较字符串的相等性,方法
.equals()
和 == 运算符都是完全有效的,区别取决于您要比较的内容或您的意图是什么想要比较两个对象String
,(按引用或按值)。字符串与任何其他对象一样是对象,但是将其与其他对象区分开来存在巨大而微妙的差异,首先您可以通过这两种方式初始化字符串。
在这两种情况下,都会创建一个对象,第一个示例中缺少运算符
new
只是一种快捷方式(因此看起来更自然)。现在你要了解 Java 是如何管理字符串的,在 Java 中有一个字符串池,这是为存储字符串而保留的内存空间,应用程序通常会大量使用字符串,只有这些在运行时最多可以占用 40% 的内存并且其中许多字符串是重复的,例如“a”“en”“la”等。为了优化这一点,Java 将所有这些字符串作为文字收集在 JVM 位置并重用重复的文字以优化内存使用,因此如果将文字“carlos”存储在两个变量中,Java 将重用此文字。
因此,如果您声明以下变量
String
并使用相同的文字初始化它们。(记住你正在创建两个对象)与 == 运算符的比较将返回 true,因为字符串池回收了文字“carlos”,因此它们是相同的引用,因此进行比较是完全有效的。
字符串池只回收和存储字面量,这意味着如果你创建一个字符串如下
由于它不是用java字面量初始化的,所以它不会被存储在String Pool中,也不会被回收,因此会被Garbage Collector淘汰,如果是这种情况,那么下面的比较将导致false。
这就是为什么当您使用 == 运算符进行比较时,它有时会返回 true,有时会返回 false,即使您正在比较字符串中的相同值。
.equals 方法用于按值或逐字符比较字符串,这是一种安全的字符串比较方法,因为请记住,在第一个示例中,我们在技术上使用 == 运算符进行了按值比较由于字符串池的特殊性。
如果您想知道,如果在通过文字初始化字符串时,值存储在字符串池中,那么当我修改字符串时会发生什么?
还有一点,Java 中的字符串是不可变的,这意味着您不能修改它们的值,例如向 String 值添加更多字符,Java 不提供任何 API 来直接修改 String。(然而 Java 提供了一个 API 可以间接地做到这一点)
例如,如果我想将姓氏添加到我的变量 (name),我可以做的是为变量 (name)重新分配一个新字符串,我将通过将原始值与姓氏连接来构建这边走。
这样做是创建一个新值“carlos lucero”并将该值分配给名称字符串。
现在,如果我现在将 'name' 与包含与 'name' 相同的值但被分配为文字的新变量进行比较,会发生什么?
好吧,由于变量(名称)被重新分配给了一个不是通过文字创建的新值,现在变量(名称)不再在字符串池中,因此它的引用不会被回收并且与如果它是通过文字创建的变量 (FullName) 将给出 False 作为结果。
最后,Java 提供了一个 API 来解决字符串不变性问题,这个 API 是由类公开的
StringBuilder
。如前所述,== 操作符在原语的情况下确认值是相同的,在引用指向同一对象的对象的情况下。
关于equals()方法还有一点需要解释 ,Java 中的所有类都是Object的子类,object 带有一个默认的equals()声明。
如果我声明一个新类,我的类的其他用户希望我实现一个equals(Object o)方法,这意味着两个对象被认为是相等的。这并不一定意味着它们是,并且可能需要文档中的注释。一个例子:
如果我声明一个 Point 的子类,其标签如下:
我应该评论说,如果坐标匹配,则无论标签如何,两个NamedPoints都被认为是相等的。
请注意,简单地覆盖该方法并不能确保我的逻辑的一致性。如果我在NamedPoint中覆盖equals以也考虑标签,我会遇到以下问题:
为了避免这种歧义,您可以比较类而不是使用 instanceof:
总结:在平等问题上有龙。
== 运算符通常在变量已经初始化时工作,因为它比较内部表示,但最正确的方法是使用从 class 继承的 equals 方法进行比较
Object
。使用 equals 比较它们几乎总是最好的解决方案
但是尽管如此,如果您的虚拟机比 Tiger 小,您可能会遇到问题,因为在不幸的实现中,定义为的字符串
null
与空字符串不同。因此,对于这些情况,您可以使用运算符进行比较
==
或者有很多保留,比较内部表示。
"==" 用于 Integer、Char、Object 或 null 等,最好使用 equals 或 equalsIgnoreCase:
仅对于原始类型,比较 == 通常有效。对于对象,应该使用比较方法,因为
equals()
它可能对Strings
. 对于其他类型的对象,这种类型的比较可能无效。使用 == 比较引用,而不是内存中对象的内容。
比较 2 个字符串的正确方法是使用equals()函数,即比较 2 个字符串和相同但忽略大小写的equalsIngnoreCase() 。
测试: