将字符串与空字符串进行比较 (Java)

2022-09-01 03:23:18

我有一个关于在Java中将字符串与空字符串进行比较的问题。如果我将字符串与空字符串进行比较,是否有区别?例如:==equals

String s1 = "hi";

if (s1 == "")

if (s1.equals("")) 

我知道应该将字符串(以及一般的对象)与 ,而不是 进行比较,但我想知道它对空字符串是否重要。equals==


答案 1
s1 == ""

不可靠,因为它测试的是引用相等性而不是对象相等性(并且 String 不是严格规范的)。

s1.equals("")

更好,但可能会遭受空指针异常的影响。更好的是:

"".equals(s1)

没有空指针异常。

编辑:好吧,这一点被问及规范形式。本文将其定义为:

假设我们有一些集合 S 的对象,具有等价关系。规范形式是通过将S的某些对象指定为“规范形式”来给出的,这样所考虑的每个对象都只等价于规范形式的一个对象。

举一个实际的例子:以有理数的集合为例(或者“分数”通常被称为”有理数由分子和除数(除数)组成,两者都是整数。这些有理数是等价的:

3/2, 6/4, 24/16

有理数 nubmers 通常写成 gcd(最大公约数)为 1。因此,所有这些都将简化为3/2。3/2可以被看作是这组有理数的规范形式

那么,当使用术语“规范形式”时,它在编程中意味着什么呢?它可能意味着几件事。以这个虚构的类为例:

public class MyInt {
  private final int number;

  public MyInt(int number) { this.number = number; }
  public int hashCode() { return number; }
}

类 MyInt 的哈希代码是该类的规范形式,因为对于 MyInt 的所有实例的集合,您可以采用任意两个元素 m1 和 m2,它们将遵循以下关系:

m1.equals(m2) == (m1.hashCode() == m2.hashCode())

这种关系是规范形式的本质。更常见的出现方式是当您对类使用工厂方法时,例如:

public class MyClass {
  private MyClass() { }

  public MyClass getInstance(...) { ... }
}

无法直接实例化实例,因为构造函数是私有的。这只是一种工厂方法。工厂方法允许您执行的操作如下:

  • 始终返回相同的实例(抽象的单例);
  • 只需在每次调用时创建一个新的ints;
  • 规范形式返回对象(稍后将对此进行详细介绍);或
  • 无论你喜欢什么。

基本上,工厂方法抽象了对象创建,我个人认为强制所有构造函数都是私有的以强制使用此模式将是一个有趣的语言功能,但我离题了。

您可以使用此工厂方法执行哪些操作,方法是缓存您创建的实例,以便对于任何两个实例 s1 和 s2,它们都遵循以下测试:

(s1 == s2) == s1.equals(s2)

因此,当我说String不是严格规范的时,这意味着:

String s1 = "blah";
String s2 = "blah";
System.out.println(s1 == s2); // true

但是,正如其他人所指出的那样,您可以使用以下命令来更改此设置:

String s3 = new String("blah");

并可能:

String s4 = String.intern("blah");

所以你不能完全依赖参考平等,所以你根本不应该依赖它。

作为上述模式的警告,我应该指出,使用私有构造函数和工厂方法控制对象创建并不能保证引用相等意味着由于序列化而导致的对象相等。序列化绕过正常的对象创建机制。Josh Bloch 在 Effective Java 中介绍了这个主题(最初是在第一版中,当时他谈到了类型安全的枚举模式,该模式后来成为 Java 5 中的一种语言特性),您可以通过重载(私有)readResolve() 方法来绕过它。但这很棘手。类装入器也会影响此问题。

无论如何,这是规范形式。


答案 2

这将取决于字符串是否是文本。如果创建字符串时

new String("")

然后,它永远不会将 “” 与 equals 运算符匹配,如下所示:

    String one = "";
    String two = new String("");
    System.out.println("one == \"\": " + (one == ""));
    System.out.println("one.equals(\"\"): " + one.equals(""));
    System.out.println("two == \"\": " + (two == ""));
    System.out.println("two.equals(\"\"): " + two.equals(""));

--

one == "": true
one.equals(""): true
two == "": false
two.equals(""): true

基本上,您希望始终使用 equals()