String.equals 与 == [duplicate]

String.equals versus == [duplicate]

提问人:franvergara66 提问时间:4/20/2009 最后编辑:codeforesterfranvergara66 更新时间:9/4/2018 访问量:941050

问:

此代码将字符串分成标记并将它们存储在字符串数组中,然后将变量与第一个主目录进行比较。为什么它不起作用?

public static void main(String...aArguments) throws IOException {

    String usuario = "Jorman";
    String password = "14988611";

    String strDatos = "Jorman 14988611";
    StringTokenizer tokens = new StringTokenizer(strDatos, " ");
    int nDatos = tokens.countTokens();
    String[] datos = new String[nDatos];
    int i = 0;

    while (tokens.hasMoreTokens()) {
        String str = tokens.nextToken();
        datos[i] = str;
        i++;
    }

    //System.out.println (usuario);

    if ((datos[0] == usuario)) {
        System.out.println("WORKING");
    }
}
Java 字符串

评论

2赞 Prasad Kharkar 9/26/2013
看看这个 thejavageek.com/2013/07/27/...
3赞 mani deepak 1/27/2014
“==”比较的是引用,而不是内容。将 datos[0] == usuario 更改为 datos[0].equals(usuario) 以获得正确答案
2赞 Alnitak 7/19/2014
我看到你改变了你接受的答案 - 我敦促你阅读我对此的评论并重新考虑。现在接受的答案中的“故事”最初可能看起来不错,但恕我直言,它真的经不起推敲。
0赞 LordWabbit 9/5/2020
大多数语言都是这样工作的,你只是看不到它,因为大多数语言都有运算符重载,字符串的 == 运算符已被重载以调用等效于 string.equals 的语言。Java 没有运算符重载,所以你必须像穴居人一样艰难地做到这一点。以这种方式比较字符串时,Java 也不会抱怨或警告您,因此它成为您可以追踪的运行时错误。为什么 Java 没有运算符重载?因为他们想保持语言简单,所以他们意识到它太简单了,这使得处理日期变得复杂。

答:

608赞 Alnitak 4/20/2009 #1

使用 string.equals(Object other) 函数比较字符串,而不是运算符。==

该函数检查字符串的实际内容,运算符检查对对象的引用是否相等。请注意,字符串常量通常是“内部”的,因此实际上可以比较两个具有相同值的常量,但最好不要依赖它。====

if (usuario.equals(datos[0])) {
    ...
}

注意:比较是在“usuario”上完成的,因为它在你的代码中保证不为空,尽管你仍然应该检查数组中是否确实有一些标记,否则你会得到一个数组越界异常。datos

评论

10赞 user unknown 5/16/2012
@mo:正如你从这个例子中看到的那样,它没有得到平等的处理。
57赞 Jon Taylor 7/24/2012
@mo在某些情况下,即使在 java == 中也可能具有误导性。Java 缓存字符串,因此类似的东西将返回 true。 尽管人们通常认为结果是错误的。String a = "Hello"; String b = "Hello"; a == b is true
7赞 parasietje 9/19/2013
@JonTaylor 您的示例与缓存无关。在 java 代码中键入“Hello”实际上会在类中创建一个匿名的静态 String 对象。如果您使用的是一个好的编译器,则多次出现的“Hello”可能会使用相同的静态 String 对象,但将“Hello”替换为new String(new char[] {'H', 'e', ...})
10赞 fgb 10/5/2013
@parasietje JLS 保证多次出现的“Hello”(作为文本)引用同一个 String 对象。编译器不能用其他东西替换它。
5赞 Galax 5/20/2016
使用时要非常小心,除非两者都使用文字初始化,否则将始终返回 false。例如,这将打印 false====String a = "abc"; String b = "abcd"; a += "d"; System.out.println(a == b);
26赞 Bhushan Bhangale 4/20/2009 #2

而不是

datos[0] == usuario

datos[0].equals(usuario)

==比较变量的引用,其中比较您想要的值。.equals()

评论

11赞 Steve Kuo 4/20/2009
只需确保左侧不为 null 即可
0赞 11/6/2012
或者改用 usario.equals,就像 @Alnitak 所展示的选定答案一样。如果您最初知道 usario 不是 null,它会为您节省一个步骤(或一大堆)。
11赞 Michael Klement 4/20/2009 #3

您应该使用字符串等于来比较两个字符串是否相等,而不是运算符 ==,它只是比较引用。

103赞 Michal Bernhard 4/20/2009 #4

值得一提的是,在某些情况下,使用“==”运算符可以产生预期的结果,因为 java 处理字符串的方式 - 字符串文字在编译过程中被嵌入(参见 ) - 因此,当您在两个类中编写示例并将这些字符串与“==”进行比较时,您可以得到 result: true,这是根据规范预期的;当您比较相同的字符串(如果它们具有相同的值)时,第一个是字符串文字(即通过 定义),第二个是在运行时构造的,即。对于 “new” 关键字,(equality) 运算符返回 false,因为它们都是类的不同实例。String.intern()"hello world""i am string literal"new String("i am string literal")==String

唯一正确的方法是使用 .equals() -> datos[0].equals(usuario)。 仅当两个对象是对象的相同实例(即具有相同的内存地址)时才表示==

更新:01.04.2013 我更新了这篇文章,因为下面的评论在某种程度上是正确的。最初我声明实习(String.intern)是JVM优化的副作用。虽然它确实节省了内存资源(这就是我所说的“优化”的意思),但它主要是语言的特性

评论

6赞 x4u 2/6/2010
这实际上不仅仅是 jvm 优化的副作用,与编译器完全无关。根据 Java VM 规范,所有类中的静态字符串(文本)的标识得到保证,并且适用于至少与 Java 1.1 兼容的每个 VM。
7赞 Michal Bernhard 7/15/2011
如果你指的是 JVM 规范第 2.3 章“字符串文字,更一般地说,作为常量表达式值的字符串被”interned“,以便使用 String.intern 方法共享唯一实例”。好吧,它是由 jvm 保证的(根据规范),但对我来说,这仍然意味着优化。此 AFAIK 没有语义值。另一方面,== 具有语义上的“身份相等”,而方法 equals() 具有“对象相等”,因此您应该遵守这一点,而不是依赖 jvm 规范,这是 jvm 实现者的“指南”,而不是开发人员的“指南”(他们有 Java 语言规范)。
3赞 bestsss 6/7/2012
文字、类名等被隔离以符合规范,这不仅仅是优化。“xxx” 始终是 == “xxx”,这是语言设计的一部分,而不是 impl。详细信息/指南。
1赞 Stultuske 5/8/2015
实际上,使用 == 总是返回预期的结果。问题在于有些人对结果有错误的期望。这不是语言的问题,而是他们缺乏知识的问题。如果他们希望 == 始终返回与 .equals 的结果相同的结果,他们应该重新阅读他们的教科书。另一方面,如果他们希望 == 返回引用的比较,他们会注意到它总是返回他们期望的内容。
11赞 finnw 2/6/2010 #5

如果您在将字符串插入数组之前调用该字符串,它也将起作用。 当且仅当被隔离的字符串的值等于 (.) 时,它们才是引用相等的 ()intern()==equals()

public static void main (String... aArguments) throws IOException {

String usuario = "Jorman";
String password = "14988611";

String strDatos="Jorman 14988611";
StringTokenizer tokens=new StringTokenizer(strDatos, " ");
int nDatos=tokens.countTokens();
String[] datos=new String[nDatos];
int i=0;

while(tokens.hasMoreTokens()) {
    String str=tokens.nextToken();
    datos[i]= str.intern();            
    i++;
}

//System.out.println (usuario);

if(datos[0]==usuario) {  
     System.out.println ("WORKING");    
}
38赞 HariShankar 3/11/2012 #6

equals()函数是一种类方法,应该由程序员重写。 类覆盖它以检查两个字符串是否相等,即在内容而不是引用中。ObjectString

==运算符检查两个对象的引用是否相同。

考虑程序

String abc = "Awesome" ;
String xyz =  abc;

if(abc == xyz)
     System.out.println("Refers to same string");

这里的 和 ,都是指相同的。因此表达式是 。abcxyzString"Awesome"(abc == xyz)true

String abc = "Hello World";
String xyz = "Hello World";

if(abc == xyz)
    System.out.println("Refers to same string");
else
    System.out.println("Refers to different strings");

if(abc.equals(xyz))
     System.out.prinln("Contents of both strings are same");
else
     System.out.prinln("Contents of strings are different");

这里是两个内容相同的不同字符串。因此,这里的表达式是 where as is .abcxyz"Hello World"(abc == xyz)false(abc.equals(xyz))true

希望您了解 和 之间的区别==<Object>.equals()

谢谢。

评论

0赞 Chibueze Opata 3/11/2012
我想知道,在什么(非显而易见的)情况下,abc == xyz 会起作用?
7赞 arun 10/25/2012
代码输出(将 prinln 固定到 println 之后):引用相同的字符串,两个字符串的内容相同,即这里 (abc == xyz) 和 (abc.equals(xyz)) 都是真的!
6赞 tObi 9/16/2013
如上所述,这个答案是错误的。由于实习优化机制,有时 2 个内容相同的字符串对象实际上只由一个对象表示。这种优化是可能的,因为字符串是不可变的
0赞 mavis 10/26/2017
stackoverflow.com/a/513839/1889167 有详细的答案!
12赞 Harry He 3/12/2012 #7

我们来分析一下下面的 Java,来理解 String 的恒等性和相等性:

public static void testEquality(){
    String str1 = "Hello world.";
    String str2 = "Hello world.";

    if (str1 == str2)
        System.out.print("str1 == str2\n");
    else
        System.out.print("str1 != str2\n");

    if(str1.equals(str2))
        System.out.print("str1 equals to str2\n");
    else
        System.out.print("str1 doesn't equal to str2\n");

    String str3 = new String("Hello world.");
    String str4 = new String("Hello world.");

    if (str3 == str4)
        System.out.print("str3 == str4\n");
    else
        System.out.print("str3 != str4\n");

    if(str3.equals(str4))
        System.out.print("str3 equals to str4\n");
    else
        System.out.print("str3 doesn't equal to str4\n");
}

当第一行代码执行时,将创建一个字符串,变量引用它。由于优化,当下一行代码执行时,不会再次创建另一个字符串。该变量还指现有的 .String str1 = "Hello world."\Hello world."str1"Hello world."str2""Hello world."

运算符检查两个对象的标识(两个变量是否引用同一对象)。由于 和 引用内存中的相同字符串,因此它们彼此相同。该方法检查两个对象是否相等(两个对象是否具有相同的内容)。当然,和的内容是一样的。==str1str2equalsstr1str2

当代码执行时,将创建一个包含内容的字符串的新实例,并由变量 引用。然后再次创建另一个包含内容的字符串实例,并由 引用。由于 和 指的是两个不同的实例,因此它们并不相同,但它们 内容是一样的。String str3 = new String("Hello world.")"Hello world."str3"Hello world."str4str3str4

因此,输出包含四行:

Str1 == str2

Str1 equals str2

Str3! = str4

Str3 equals str4

评论

0赞 user unknown 5/16/2012
你不应该覆盖你的类的等号。你可能会这样做,在某些情况下你应该这样做。为什么我要在 FooDialog 中覆盖 XyPanel 中的等值?
8赞 Himanshu Mohta 5/16/2012 #8

==运算符比较 Java 中对象的引用。您可以使用字符串的方法。equals

String s = "Test";
if(s.equals("Test"))
{
    System.out.println("Equal");
}
9赞 mreaevnia 9/7/2012 #9

如果您要比较字符串的任何赋值,即原始字符串,“==”和 .equals 都可以使用,但对于新的字符串对象,您应该只使用 .equals,这里的“==”将不起作用。

例:

String a = "name";

String b = "name";

if(a == b)并将返回 true。(a.equals(b))

String a = new String("a");

在这种情况下将返回if(a == b)false

所以最好使用运算符....equals

3赞 Harrydev 10/22/2012 #10

使用 Split 而不是 tokenizer,它肯定会提供准确的输出 例如:

string name="Harry";
string salary="25000";
string namsal="Harry 25000";
string[] s=namsal.split(" ");
for(int i=0;i<s.length;i++)
{
System.out.println(s[i]);
}
if(s[0].equals("Harry"))
{
System.out.println("Task Complete");
}

在此之后,我相信你会得到更好的结果......

8赞 Abhinav Jayaram 12/3/2012 #11

通常用于比较,其中要验证两者是否具有相同的值。.equalsObjectObjects

==用于参考比较(两者在堆上是否相同)并检查是否为 null。它还用于比较基元类型的值。ObjectsObjectObject

6赞 engy 12/6/2012 #12

== 运算符是值的简单比较。
对于对象引用,(值)是(引用)。因此,如果 x 和 y 引用同一对象,则 x == y 返回 true。

6赞 tinker_fairy 12/10/2012 #13

@Melkhiah66 您可以使用 equals 方法代替 '==' 方法来检查是否相等。 如果使用 intern(),则检查对象是否在池中(如果存在),则返回 等于否则不相等。equals 方法在内部使用哈希码并为您提供所需的结果。

public class Demo
{
  public static void main(String[] args)
  {
              String str1 = "Jorman 14988611";
    String str2 = new StringBuffer("Jorman").append(" 14988611").toString();
    String str3 = str2.intern();
    System.out.println("str1 == str2 " + (str1 == str2));           //gives false
    System.out.println("str1 == str3 " + (str1 == str3));           //gives true
    System.out.println("str1 equals str2 " + (str1.equals(str2)));  //gives true
    System.out.println("str1 equals str3 " + (str1.equals(str3)));  //gives true
  }
}

6赞 Raekye 12/20/2012 #14

我知道这是一个老问题,但这是我如何看待它(我发现非常有用):


技术说明

在 Java 中,所有变量要么是原始类型,要么是引用

(如果你需要知道什么是引用:“对象变量”只是指向对象的指针。因此,某些东西实际上是内存中的地址(一个数字)。Object something = ...

==比较确切的值。因此,它会比较原始值是否相同,或者引用(地址)是否相同。这就是为什么通常不适用于字符串的原因;字符串是对象,对两个字符串变量执行操作只是比较内存中的地址是否相同,正如其他人指出的那样。 调用对象的比较方法,该方法将比较引用指向的实际对象。对于字符串,它会比较每个字符以查看它们是否相等。====.equals()


有趣的部分

那么,为什么有时字符串会返回 true?请注意,字符串是不可变的。在代码中,如果这样做==

String foo = "hi";
String bar = "hi";

由于字符串是不可变的(当你调用或某些东西时,它会生成一个新字符串,而不是修改内存中指向的原始对象),所以你实际上不需要两个不同的对象。如果编译器是智能的,则字节码将读取为仅生成一个对象。所以如果你这样做.trim()String("hi")String("hi")

if (foo == bar) ...

紧接着,它们指向同一个对象,并将返回 true。但你很少打算这样做。相反,你要求用户输入,即在内存的不同部分创建新的字符串,等等。

注意:如果你做了类似的事情,编译器可能仍然会发现它们是一回事。但重点是,当编译器看到文字字符串时,它可以轻松优化相同的字符串。baz = new String(bar)

我不知道它在运行时是如何工作的,但我假设 JVM 不保留“实时字符串”列表并检查是否存在相同的字符串。(例如,如果您两次读取一行输入,并且用户输入两次相同的输入,则不会检查第二个输入字符串是否与第一个输入字符串相同,并将它们指向相同的内存)。这样可以节省一些堆内存,但可以忽略不计,开销不值得。同样,关键是编译器很容易优化文字字符串。

你有它......对 VS 的坚韧不拔的解释。 以及为什么它看起来是随机的。==.equals()

29赞 Puneet Purohit 1/4/2013 #15

==参考相等性测试。

.equals()价值相等性测试。

因此,如果你真的想测试两个字符串是否具有相同的值,你应该使用(除了在少数情况下,你可以保证两个具有相同值的字符串将由同一个对象表示,例如:实习)。.equals()String

==用于测试两个字符串是否相同。Object

// 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 

// concatenation of string literals happens at compile time resulting in same objects
"test" == "te" + "st"  ==> true

// but .substring() is invoked at runtime, generating distinct objects
"test" == "!test".substring(1) ==> false

需要注意的是,它比(单个指针比较而不是循环)便宜得多,因此,在它适用的情况下(即,您可以保证只处理被隔离的字符串),它可以提供重要的性能改进。但是,这些情况很少见。==equals()

评论

0赞 Swadhikar 7/6/2016
这是到目前为止我看到的关于这个问题的最简单的答案。谢谢。
0赞 MinteZ 8/18/2017
关于子字符串,如果将 == 用于相同的字符串,并且其中一个是另一个字符串的子字符串,则 == 将返回 true。例如,这个(至少在我测试它时)打印 true:String str = "abcdef"; System.out.println(str == str.substring(0, str.length()));
593赞 Jops 4/24/2013 #16

认识 Jorman

Jorman是一位成功的商人,拥有2栋房屋。

enter image description here

但其他人不知道。

是同一个乔曼吗?

当你问麦迪逊街或伯克街的邻居时,他们只能说:

enter image description here

仅使用住所,很难确认它是同一个乔曼。由于它们是 2 个不同的地址,因此很自然地假设它们是 2 个不同的人。

这就是运算符 == 的行为方式。所以它会说这是错误的,因为它只比较地址datos[0]==usuario

救援调查员

如果我们派一个调查员呢?我们知道这是同一个乔曼,但我们需要证明这一点。我们的侦探将仔细观察所有物理方面。通过彻底的调查,代理人将能够得出结论,这是否是同一个人。让我们看看它在 Java 术语中的发生。

下面是 String 方法的源代码:equals()

enter image description here

它逐个字符比较字符串,以便得出结论,它们确实是相等的。

这就是 String equals 方法的行为方式。因此将返回 true,因为它执行逻辑比较datos[0].equals(usuario)

评论

27赞 Nader Ghanbari 5/4/2014
我喜欢直观的例子,这是我见过的最好的例子之一。新手程序员可以很容易地理解幕后发生的事情。
15赞 Alnitak 7/19/2014
我实际上认为这个答案真的很令人困惑,因为它将人的名字人本身混为一谈。它还混淆了“平等”和“等同”。从语义上讲,检查完全是一个测试,即一个人正在比较相同的两个对象(相等),因此根据定义,它必须是等价的。循环之后的最后一个并不意味着我们有相同的“Jorman”,它意味着两个实体共享相同的值(等价),这并不意味着相等。(在这方面,Java 方法被错误地命名了)。this == anObjectreturn truewhile.equals
1赞 Gsv 10/24/2014
这个答案是给新手的,下一个答案,Michal Bernhard 的答案提供了对 Java 应用于字符串时 == 不一致行为的正确分析。
3赞 Raymond Chenon 5/20/2015
@DavidT。您忘记了指纹检查:)
2赞 1/15/2016
-1因为没有手绘的红圈 - 说真的,对于乔曼家伙来说。+1
4赞 Dinoop Nair 4/29/2013 #17

将检查两个字符串是否具有相同的值并返回值,因为运算符会检查这两个字符串是否是同一个对象。.equals()boolean==

4赞 Keith Spriggs 5/31/2013 #18

有人在更高的帖子上说 == 用于 int 和检查 null。 它还可用于检查布尔运算和字符类型。

不过要非常小心,并仔细检查您使用的是 char 而不是 String。 例如

    String strType = "a";
    char charType = 'a';

对于字符串,您将检查 这是正确的

    if(strType.equals("a")
        do something

    if(charType.equals('a')
        do something else

不正确,您需要执行以下操作

    if(charType == 'a')
         do something else
38赞 Aniket Thakur 7/25/2013 #19
The == operator checks if the two references point to the same object or not.
.equals() checks for the actual string content (value).

请注意,.equals() 方法属于类 Object(所有类的超类)。您需要根据类要求覆盖它,但对于 String,它已经实现,它会检查两个字符串是否具有相同的值。

Case1)
String s1 = "Stack Overflow";
String s2 = "Stack Overflow";
s1 == s1;      // true
s1.equals(s2); // true
Reason: String literals created without null are stored in the string pool in the permgen area of the heap. So both s1 and s2 point to the same object in the pool.
Case2)
String s1 = new String("Stack Overflow");
String s2 = new String("Stack Overflow");
s1 == s2;      // false
s1.equals(s2); // true
Reason: If you create a String object using the `new` keyword a separate space is allocated to it on the heap.

评论

0赞 wisbucky 2/15/2018
这是最简单的答案,清楚地展示了不同的情况。
1赞 wisbucky 2/15/2018
我还要为 Case2 再举 2 个例子:和 .这演示了将对象与文本进行比较。s1 == "Stack Overflow" // falses1.equals("Stack Overflow") // true
4赞 rohan kamat 10/24/2013 #20

a==b

比较引用,而不是值。with 对象引用的使用通常仅限于以下几种:==

  1. 比较以查看引用是否为 .null

  2. 比较两个枚举值。这之所以有效,是因为每个常量只有一个对象。enum

  3. 您想知道两个引用是否指向同一对象

"a".equals("b")

比较值是否相等。由于此方法是在类中定义的,所有其他类都是从该类派生的,因此会自动为每个类定义此方法。但是,它不会对大多数类执行智能比较,除非类覆盖它。对于大多数 Java 核心类来说,它都是以一种有意义的方式定义的。如果未为(用户)类定义它,则其行为与 相同。Object==