目前我在程序中一直使用==
运算符来比较所有的字符串。然而,我遇到了一个错误,将其中一个用.equals()
替换后,问题被解决了。
==
是否不好?应该何时使用或不使用?有什么区别?
==
测试引用相等性(即它们是否是同一个对象)。
.equals()
测试值相等性(即它们是否包含相同的数据)。
Objects.equals()在调用.equals()
之前检查null
,因此您不必自己检查(JDK7及以上版本可用,也可在Guava中使用)。
因此,如果您想测试两个字符串是否具有相同的值,您可能会想要使用Objects.equals()
。
// These two have the same value
new String("test").equals("test") // --> true
// ... but they are not the same object
new String("test") == "test" // --> false
// ... neither are these
new String("test") == new String("test") // --> false
// ... but these are because literals are interned by
// the compiler and thus refer to the same object
"test" == "test" // --> true
// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true
// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true
==
和!=
中可以得知:
你几乎总是要使用虽然
==
可以用于比较String
类型的引用,但这种相等测试确定两个操作数是否引用同一个String
对象。如果操作数是不同的String
对象,即使它们包含相同的字符序列(§3.10.5,§3.10.6),结果也是false
。可以通过方法调用s.equals(t)
来测试两个字符串s
和t
的内容是否相等。
Objects.equals()
。在罕见的情况下,你知道你正在处理interned字符串时,你可以使用==
。在JLS 3.10.5-1中也可以找到类似的例子。此外,字符串字面值始终引用类
String
的相同实例。这是因为字符串字面值 - 或者更一般地说,作为常量表达式值的字符串(§15.28) - 被“interned”以共享唯一实例,使用方法String.intern
。
String.equalsIgnoreCase()忽略大小写的值相等性。但要注意,在不同的区域设置相关情况下,该方法可能会产生意外的结果,请参考this question。
String.contentEquals()将String
的内容与任何CharSequence
的内容进行比较(自Java 1.5起可用)。这样可以避免在进行相等性比较之前将StringBuffer等转换为String,但空值检查留给您自己处理。
==
比较的是变量的值,所以当你有一个对象时,引用该对象的变量将其引用作为值。因此,使用==
比较两个变量时,要比较它们的引用。对于诸如int
这样的基本数据类型,情况仍然相同。int
类型的变量具有整数值。因此,使用==
比较两个int
的值。无论int
是变量的值还是魔数都没有关系。此外,引用只是一个指向内存的数字。 - akuzminykhequals
,因为这样更明显正确。或者,你应该使用枚举而不是字符串。 - kaya3Objects
),且名称来自英语,我认为他们保留了方法名.equals
而不是将其更改为.equal
,这让我感到不协调。 - Karl Knechtel==
测试对象引用,.equals()
测试字符串值。
有时候看起来好像 ==
比较的是值,因为Java在幕后做了一些工作,以确保相同的内联字符串实际上是同一个对象。
例如:
String fooString1 = new String("foo");
String fooString2 = new String("foo");
// Evaluates to false
fooString1 == fooString2;
// Evaluates to true
fooString1.equals(fooString2);
// Evaluates to true, because Java uses the same object
"bar" == "bar";
但要小心null值!
==
可以很好地处理null
字符串,但是从一个null
字符串调用.equals()
会引发异常:
String nullString1 = null;
String nullString2 = null;
// Evaluates to true
System.out.print(nullString1 == nullString2);
// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));
所以如果你知道fooString1
可能是空的,那么请通过写出来告诉读者。
System.out.print(fooString1 != null && fooString1.equals("bar"));
以下代码更短,但不太明显地检查了空值:System.out.print("bar".equals(fooString1)); // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar")); // Java 7 required
==
比较对象引用。
.equals()
比较字符串值。
有时==
会在以下情况下产生比较字符串值的错觉:
String a="Test";
String b="Test";
if(a==b) ===> true
这是因为当你创建任何字符串文字时,JVM首先在字符串池中搜索该文字,并且如果找到匹配项,则会将相同的引用赋给新字符串。因此,我们得到:
(a==b) ===> true
String Pool
b -----------------> "test" <-----------------a
然而,==
在以下情况下会失败:
String a="test";
String b=new String("test");
if (a==b) ===> false
在这种情况下,对于new String("test")
,将在堆上创建新的字符串对象,然后该引用将被赋给b
,因此b
将被赋予堆上的引用,而不是字符串池中的引用。a
指向字符串池中的一个字符串,而b
指向堆上的一个字符串。因此我们得到:
if(a==b) ===> false.
String Pool
"test" <-------------------- a
Heap
"test" <-------------------- b
.equals()
方法始终比较 String 值,因此在两种情况下都返回 true:
.equals()
方法永远比较字符串的内容,而不是引用或内存地址。
String a="Test";
String b="Test";
if(a.equals(b)) ===> true
String a="test";
String b=new String("test");
if(a.equals(b)) ===> true
因此,始终使用.equals()
更好。
.equals()
方法比较的是实例(引用/地址),而String类的.equals()
方法被重写为比较内容(字符)。 - kittuString
对象以节省内存占用,因为众所周知 String
是不可变的(我希望我在这里表达得正确)。还可以查看https://dev59.com/6XA75IYBdhLWcg3w4tR7 - Roland==
操作符用于检查两个字符串是否完全相同。
.equals()
方法将检查两个字符串是否具有相同的值。
Java中的字符串是不可变的。这意味着每当您尝试更改/修改字符串时,都会得到一个新实例。您无法更改原始字符串。这样做是为了可以对这些字符串实例进行缓存。典型的程序包含许多字符串引用,缓存这些实例可以减少内存占用并提高程序性能。
当使用==运算符进行字符串比较时,您并没有比较字符串的内容,而是实际上在比较内存地址。如果它们都相等,则返回true,否则返回false。而在字符串中equals比较字符串内容。
那么问题是,如果所有字符串都被缓存在系统中,为什么 ==
返回false,而equals返回true?嗯,这是可能的。如果您创建一个像String str = new String(“ Testing”)
的新字符串,即使缓存已经包含具有相同内容的字符串,您也会在缓存中创建一个新字符串。简而言之,"MyString" == new String("MyString")
将始终返回false。
Java还谈论了可以在字符串上使用的intern()函数,使其成为缓存的一部分,因此"MyString" == new String("MyString").intern()
将返回true。
注意:==运算符比equals运算符快得多,只是因为您正在比较两个内存地址,但您需要确保代码不会在代码中创建新的String实例。否则,您将遇到错误。
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true
确保你理解为什么。这是因为==
比较只比较引用;而equals()
方法则对内容逐个字符进行比较。
当你为a
和b
调用new
时,每个变量都会得到一个指向字符串表中的"foo"
的新引用。引用不同,但内容相同。
是的,这很糟糕...
==
表示你的两个字符串引用是完全相同的对象。你可能听说过这是因为Java保留了一种字面表(确实如此),但并不总是这样。有些字符串以不同的方式加载,从其他字符串构建等,所以你绝不能假定两个相同的字符串存储在同一位置。
Equals 方法为你进行了实际比较。
是的,==
不适用于比较字符串(任何对象实际上都不适用,除非您知道它们是规范的)。==
只是比较对象引用。 .equals()
则测试相等性。对于字符串来说,通常它们会相同,但正如你所发现的那样,并不总是保证相同。
==
运算符比较两个对象时,它会将地址相等性与字符串池进行比较。如果两个String对象具有相同的地址引用,则返回true
,否则返回false
。但是,如果您想比较两个字符串对象的内容,则必须覆盖equals
方法。
equals
实际上是Object类的方法,但是它被重写为String类,并提供了一个新的定义,用于比较对象的内容。Example:
stringObjectOne.equals(stringObjectTwo);
但请注意,它会尊重字符串的大小写。如果您想进行不区分大小写的比较,则必须使用String类的equalsIgnoreCase方法。
让我们看一下:
String one = "HELLO";
String two = "HELLO";
String three = new String("HELLO");
String four = "hello";
one == two; // TRUE
one == three; // FALSE
one == four; // FALSE
one.equals(two); // TRUE
one.equals(three); // TRUE
one.equals(four); // FALSE
one.equalsIgnoreCase(four); // TRUE
equalsIgnoreCase
,这可能对新手比较有用。 - AmitG我同意zacherates的答案。
但是你可以在非文字直接量字符串上调用intern()
方法。
以zacherates的示例为例:
// ... but they are not the same object
new String("test") == "test" ==> false
如果将非文字字符串进行比较,结果为true
:
new String("test").intern() == "test" ==> true
==
进行字符串比较所带来的性能优势。 - Stephen C
==
在对象上运作方式的解释链接:http://stackoverflow.com/a/19966154/2284641 - Johannes H."12" == "1" + 2
是错误的(可能)。 - Flight Odyssey