【问题标题】:Why do != and == not behave like the equals method in Java? [duplicate]为什么 != 和 == 不像 Java 中的 equals 方法? [复制]
【发布时间】:2011-10-27 16:18:16
【问题描述】:

可能的重复:
Java String.equals versus ==
whats the difference between ".equals and =="

public String getName() {
    return new String("foobar");
}

if(getName() != "foobar2") {
    //Never gets executed, it should, wtf!.
}

if(!getName().equals("foobar2")) {
   //This works how it should.
}

所以是的,我的问题很简单。为什么!= 的行为与!equals() aka (not Equals) 不同。

我看不出任何一个失败的逻辑原因,在我看来,两者都是完全相同的代码,WTH。

看java运算符 http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

你可以清楚地看到 平等==!=

是相等运算符,当然我通常只在数字上使用!=。但我的思绪开始徘徊,为什么它不适用于String

编辑: 这看起来更像是实际问题..

    for (ClassGen cg : client.getClasses().values()) {
        final ConstantPoolGen cp = cg.getConstantPool();
        if(cp.lookupInteger(0x11223344) != -1) {
            for (Method m : cg.getMethods()) {  
                System.out.println("lots of class spam");
                if(m.getName() != "<init>") continue;
                System.out.println("NEVER GETS HERE, 100% SURE IT HAS CONSTRUCTOR LOL");
            }
        }
    }

【问题讨论】:

  • 我无法重现此行为:ideone.com/0GhxJ
  • 另外,!=根本!equals() 的代码不同。 != 运算符比较reference不等式,而equals()是一个方法
  • 你可能也对这个问题感兴趣:Java String.equals versus ==

标签: java equals equals-operator


【解决方案1】:

使用 != 意味着您检查内存中的实例引用,并且相同的实例会在比较时为您提供true

当您执行new String("foobar") 时,会在内存中创建一个新的“foobar”,使用== 进行比较返回false。

在该新字符串上调用 intern() 可能会改变这种行为,因为该字符串现在将被抓取或添加到字符串池中。

无论如何,使用 'equals()' 会更安全。

【讨论】:

  • 另外——你可以阅读这篇演示它的小文章——javatechniques.com/blog/string-equality-and-interning
  • ==!= 运算符不一定测试引用的按位等效性。他们测试的是两个引用是否标识相同的对象实例。某些类型的 GC 可以受益于知道自上一次主要 GC 周期以来是否已修改引用[此后未修改的引用不需要在 Eden 收集周期期间检查],并且可以合法地在如果在使用引用或将其与另一个比较时忽略该位,则用于该目的的引用。
【解决方案2】:
public static void main(String[] args) throws Exception {

    if (getName() != "foobar2") {
        System.out.println("1");
    }

    if (!getName().equals("foobar2")) {
        System.out.println("2");
    }
}

public static String getName() {
    return new String("foobar");
}

对我来说这个输出:

1
2

但是这两个检查是不等价的。第一个检查是检查 getName() 返回的对象是否与为字符串文字“foobar2”创建的对象相同,但事实并非如此。第二个检查可能是您想要的,它检查 getName() 方法返回的 String 对象的 VALUE 是否等于为“foobar2”字符串文字创建的 String 对象的 VALUE。

所以两个检查都会返回 true,第一个是因为它们不是同一个对象,第二个是因为值不一样。

【讨论】:

  • 是的,我在ideone 得到了相同的结果。我不知道 SSpoke 是如何得到上述结果的。
  • 好吧,这只是我做的一个例子..它实际上在我的程序中不起作用,我猜它的流程有点改变..它实际上在循环内部..
  • 更新后看起来更像实际代码。
【解决方案3】:

字符串是一个对象,而不是原语。 ==!= 比较两个原语。 要比较字符串,您需要遍历每个字符并按.equals() 所做的顺序比较它们。

如果您在 Java 中执行任何 OOP,您需要在想要对对象进行相等检查时覆盖 equals,如果您希望能够对它们进行排序等操作,则需要实现 Comparable 和 .compare()

下面是一个简单的equals示例:

public class Person {
    public name;

    public Person(String name) {
        this.name = name;
    }

    public boolean equals(Object o){
        if(o instanceof Person)
            if(this.name.equals(o.name))
                return true;
        return false;
    }
}

现在可以将一个人与另一个人进行比较,例如:

person1.equals(person2)

只有当两个人的名字相同时才会返回 true。您可以根据需要定义使两个对象相等的原因,但是如果对象实际上只是指向内存中同一对象的两个指针,则它们只是==

【讨论】:

  • Blah 我在 C# 中编程时仍然觉得很奇怪.. 毕竟我习惯在字符串上使用!=== .. 等等我猜这就是差异所在开始..
  • !=== 在 Java 中的工作方式与在几乎任何其他语言中的工作方式完全相同。不同之处在于您有一个原语的包装类,它是相同的,但带有一个大写字母,并且它具有诸如“equals()”之类的辅助方法,用于检查值是否相同。出于多种原因,这非常有用。
  • C# 支持运算符重载:msdn.microsoft.com/en-us/library/8edha89s(v=VS.71).aspx 所以== 可以定义为任何含义。这就是它适用于字符串的原因,但如果有人愿意,它也可以重载以执行与 != 相同的操作。 Java 不允许运算符重载,尽管它们可以处理字符串并定义 + 来进行连接。
  • 所以 boolean equals(Object o) 使用名称 == 名称,它可以实现引用相等。instanceof 检查两个类是否具有相同的签名。但是never 会检查 name 是否与 ASCII 值中的字符串相同 LOL!,除非 person1.equals(person2) 在幕后执行 String.equals().. 然后重载后等于?
  • @SSpoke 对不起哈哈,我的意思是this.name.equals(o.name)
【解决方案4】:

运算符仅适用于基元,而不适用于对象,因此必须进行字符串比较equals,因为它在对象级别进行操作。

--编辑--

我的评论更接近于“无法像在其他语言中那样以预期的方式比较对象的值”。当然,您可以使用 == 符号,但不能用于文本比较。这是每次有人从脚本语言或其他支持运算符以对字符串进行文本比较的语言迁移到 Java 时都会提出的经典问题。

【讨论】:

  • 哈哈原始也是对象不是吗?看看 Integer.class Float.class 等。它们是原语,但它们也是对象!
  • @SSpoke 原语现在不是对象。 int i = 0; 使 i 成为 int 类型的基元 Integer i = new Integer(0); 使 i 和 Integer 类型的对象。 Integer 是 int 的对象包装器,因此可以在只允许使用 Object 的地方使用它们。虽然 int 是一种原始类型。它们是不同的东西。
  • @SSpoke 正如 PaulPRO 所说,Java 原语不是对象。也就是说,Java 的 autoboxing/unboxing 让这些界限变得模糊
  • 哪里只允许使用对象?我从来没有遇到过这样的地方?它们似乎都可以很好地协同工作.. 如果您需要做一些高级整数的东西,为什么不把 Integer 做成一个工厂类呢?我就是不明白。啊..愚蠢的问题..我猜你的意思是void(Object a)可以转换成任何东西..但是你怎么把它转换成数字得到它!
  • Operators only apply to primitives, not Objects[snip] 这是不正确的。 == 运算符与对象完美配合。例如:someObj == nullsomeObj == someOtherObj
猜你喜欢
  • 2022-12-14
  • 1970-01-01
  • 1970-01-01
  • 2019-01-22
相关资源
最近更新 更多