【问题标题】:String.equals versus == [duplicate]String.equals 与 == [重复]
【发布时间】:2020-10-30 09:51:02
【问题描述】:

这段代码将一个字符串分成tokens并将它们存储在一个字符串数组中,然后将一个变量与第一个home进行比较......为什么它不起作用?

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");
    }
}

【问题讨论】:

  • "==" 比较参考而不是内容。将 datos[0] == usuario 更改为 datos[0].equals(usuario) 以获得正确答案
  • 我看到你改变了你接受的答案 - 我敦促你阅读我的 cmets 并重新考虑。现在接受的答案中的“故事”最初可能看起来不错,但恕我直言,它确实经不起推敲。
  • This article 可以帮助您理解这一点。
  • 大多数语言都以这种方式工作,您只是看不到它,因为大多数语言都有运算符重载,并且字符串的 == 运算符已重载以调用与 string.equals 等效的语言。 Java 没有运算符重载,因此您必须像穴居人一样艰难地进行操作。当以这种方式比较字符串时,Java 也不会抱怨或警告您,因此它会成为您要查找的运行时错误。为什么Java没有运算符重载?因为他们想保持语言简单,然后他们意识到它太简单了,使得处理日期变得复杂。

标签: java string


【解决方案1】:

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

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

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

注意:比较是在 'usuario' 上完成的,因为这在您的代码中保证为非 null,尽管您仍应检查您是否在 datos 数组中确实有一些标记,否则您将得到一个数组 -越界异常。

【讨论】:

  • @mo:正如您在这个例子中看到的那样,它的处理方式并不相同。
  • @mo 在某些情况下甚至在 java == 中也会产生误导。 Java 缓存字符串,所以这样的事情会返回 true。 String a = "Hello"; String b = "Hello"; a == b is true 即使人们通常认为结果是错误的。
  • @JonTaylor 您的示例与缓存无关。在 java 代码中键入“Hello”实际上会在类中创建一个匿名静态 String 对象。如果您使用的是好的编译器,多次出现的“Hello”可能使用相同的静态 String 对象,但将“Hello”替换为 new String(new char[] {'H', 'e', ...}) 也同样有效
  • @trusktr 您只能使用== 来比较已“实习”的字符串——通常是字符串常量。
  • @parasietje JLS 保证多次出现的“Hello”(作为文字)引用同一个 String 对象。编译器不能用别的东西代替它。
【解决方案2】:

认识乔曼

Jorman 是一位成功的商人,拥有 2 座房子。

但其他人不知道。

是同一个乔曼吗?

当您询问来自麦迪逊街或伯克街的邻居时,他们只能这样说:

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

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

救援调查员

如果我们派一名调查员怎么办?我们知道这是同一个 Jorman,但我们需要证明它。我们的侦探会仔细检查身体的所有方面。通过彻底询问,代理人将能够断定它是否是同一个人。让我们用 Java 术语来看看它发生的情况。

这里是String的equals()方法的源码:

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

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

【讨论】:

  • 我喜欢直观的例子,这是我见过的最好的例子之一。新手程序员阅读本文可以轻松理解幕后发生的事情。
  • 我实际上认为这个答案真的令人困惑,因为它将人的姓名人自己混为一谈。它还将“平等”与“等价”混淆了。 this == anObject 检查在语义上确切地是一个比较相同的两个对象(相等性)的测试,因此根据定义它们必须是等效的。 while 循环之后的最后一个 return true not 意味着我们有 same “Jorman”,这意味着两个实体共享相同的值(等效) not 意味着平等。 (Java.equals 方法在这方面的名称是错误的)。
  • 这个答案是给新手的,下一个答案,Michal Bernhard 的答案正确分析了 Java 在应用于字符串时 == 的不一致行为。
  • @DavidT。你忘了检查指纹:)
【解决方案3】:

值得注意的是,在某些情况下使用“==”运算符可能会导致预期的结果,因为 java 处理字符串的方式 - 字符串文字是内部的(参见 String.intern())在编译期间 - 因此,例如,当您在两个类中编写 "hello world" 并将这些字符串与“==”进行比较时,您可以获得结果:true,这是根据 specification 预期的;当您比较相同的字符串(如果它们具有相同的值)时,第一个是字符串文字(即通过"i am string literal" 定义),第二个是在运行时构造的,即。使用像new String("i am string literal") 这样的“new”关键字,==(相等)运算符返回 false,因为它们都是 String 类的不同实例。

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

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

【讨论】:

  • 其实不仅仅是jvm优化的副作用,和编译器完全没有关系。所有类中的静态字符串(文字)的标识均根据 Java VM 规范得到保证,并且适用于至少与 Java 1.1 兼容的每个 VM。
  • 如果您指的是 JVM 规范第 2.3 章“字符串文字,更一般地说,作为常量表达式值的字符串是“内部的”,以便使用 String.intern 方法共享唯一实例。嗯,它是由 jvm 保证的(根据规范),但对我来说,这仍然意味着优化。这个 AFAIK 没有语义价值。另一方面, == 具有语义“身份相等”,方法 equals() 具有“对象相等”,因此您应该遵守这一点,不要依赖 jvm 规范,这是 jvm 实现者的“指南”,而不是开发人员的“指南”(他们有 Java语言规范)。
  • 字面量、类名等都是为了符合规范而进行的,不仅仅是优化。 "xxx" 总是 == "xxx",这是语言设计的一部分,而不是 impl。细节/指南。
  • 其实,使用 == 总是会返回预期的结果。问题在于一些人对结果有错误的期望。这不是语言的问题,而是他们缺乏知识的问题。如果他们期望 == 总是返回与 .equals 的结果相同的结果,他们应该重新阅读他们的教科书。另一方面,如果他们期望 == 返回引用的比较,他们会注意到它总是会返回他们期望的结果。
【解决方案4】:

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

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

考虑程序

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

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

这里的abcxyz 都指同一个String "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");

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

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

谢谢。

【讨论】:

  • 我想知道,在什么(非显而易见的)情况下 abc == xyz 会起作用?
  • 代码输出(将prinln修改为println后):引用同一个字符串,两个字符串的内容相同,即这里(abc == xyz)和(abc.equals(xyz))都是true !
  • 如上所述,这个答案是错误的。由于实习生优化机制,有时具有相同内容的 2 个字符串对象实际上仅由一个对象表示。这种优化是可能的,因为字符串是不可变的
【解决方案5】:
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.

【讨论】:

  • 这是最简单的答案,清楚地展示了不同的情况。
  • 我会在案例 2 中再举两个例子:s1 == "Stack Overflow" // falses1.equals("Stack Overflow") // true。这演示了将对象与文字进行比较。
【解决方案6】:

代替

datos[0] == usuario

使用

datos[0].equals(usuario)

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

【讨论】:

  • 只要确保左边不为空
  • 或使用 usario.equals 代替,就像@Alnitak 选择的答案所示。如果您最初知道 usario 不为空,它会为您节省一步(或一大堆)。
【解决方案7】:

== 测试引用是否相等。

.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() 便宜得多(单指针比较而不是循环),因此,在它适用的情况下(即你可以保证你只处理实习生字符串)它可以带来重要的性能改进。但是,这些情况很少见。

【讨论】:

  • 这是迄今为止我看到的关于这个问题的最简单的答案。谢谢。
  • 关于子字符串,如果您将 == 用于相同的字符串并且其中一个是另一个的子字符串,则 == 将返回 true。例如,这个(至少在我测试它时)打印为 true:String str = "abcdef"; System.out.println(str == str.substring(0, str.length()));
【解决方案8】:

我们来分析下面的Java,来理解Strings的标识和相等性:

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."

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

当代码String str3 = new String("Hello world.") 执行时,会创建一个内容为"Hello world." 的新字符串实例,并由变量str3 引用。然后再次创建另一个内容为"Hello world." 的字符串实例,并由 str4。由于str3str4 指的是两个不同的实例,所以它们并不相同,但它们的 内容相同。

因此,输出包含四行:

Str1 == str2

Str1 equals str2

Str3! = str4

Str3 equals str4

【讨论】:

  • 你不应该为你的类重写 equals。你可能会这样做,在某些情况下你应该这样做。为什么我要在我的 XyPanel 中的 FooDialog 中覆盖 equals?
【解决方案9】:

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

【讨论】:

    【解决方案10】:

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

    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");    
    }
    

    【讨论】:

      【解决方案11】:

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

      例子:

      String a = "name";
      
      String b = "name";
      

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

      但是

      String a = new String("a");
      

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

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

      【讨论】:

        【解决方案12】:

        一般.equals 用于Object 比较,您想验证两个Objects 是否具有相同的值。

        == 用于参考比较(两个Objects 在堆上是否相同Object)& 检查Object 是否为空。它还用于比较原始类型的值。

        【讨论】:

          【解决方案13】:

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

          String s = "Test";
          if(s.equals("Test"))
          {
              System.out.println("Equal");
          }
          

          【讨论】:

            【解决方案14】:

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

            【讨论】:

              【解决方案15】:

              我知道这是一个老问题,但这是我的看法(我觉得非常有用):


              技术说明

              在 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 不会保留“活动字符串”列表并检查是否存在相同的字符串。 (例如,如果您读取一行输入两次,并且用户输入相同的输入两次,它不会检查第二个输入字符串是否与第一个相同,并将它们指向相同的内存)。它会节省一些堆内存,但开销如此微不足道,不值得。再次强调,编译器很容易优化文字字符串。

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

              【讨论】:

                【解决方案16】:

                @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
                  }
                }
                

                【讨论】:

                  【解决方案17】:

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

                  【讨论】:

                    【解决方案18】:

                    有人在上面的帖子中说 == 用于 int 和检查空值。 它也可用于检查布尔运算和字符类型。

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

                        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
                    

                    【讨论】:

                      【解决方案19】:

                      a==b

                      比较引用,而不是值。将== 与对象引用一起使用通常仅限于以下情况:

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

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

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

                      "a".equals("b")

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

                      【讨论】:

                        【解决方案20】:

                        使用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");
                        }
                        

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

                        【讨论】:

                          猜你喜欢
                          • 2011-08-13
                          • 2014-04-18
                          • 2015-08-02
                          • 1970-01-01
                          • 2022-01-21
                          • 2015-10-02
                          • 1970-01-01
                          • 2016-02-07
                          相关资源
                          最近更新 更多