比较字符串与空字符串(Java)

比较字符串与空字符串(Java),java,string,comparison,string-comparison,Java,String,Comparison,String Comparison,我有一个关于在Java中比较字符串和空字符串的问题。如果我将一个字符串与空字符串进行比较,并将其与=或等于的字符串进行比较,会有区别吗?例如: String s1 = "hi"; if (s1 == "") 或 我知道应该将字符串(以及一般的对象)与相等进行比较,而不是=,但我想知道这对空字符串是否重要。这取决于字符串是否为文本。如果您使用 new String("") 那么它将永远不会将“”与equals运算符匹配,如下所示: String one = ""; Strin

我有一个关于在Java中比较字符串和空字符串的问题。如果我将一个字符串与空字符串进行比较,并将其与
=
等于
的字符串进行比较,会有区别吗?例如:

String s1 = "hi";

if (s1 == "")


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

这取决于字符串是否为文本。如果您使用

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


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

一个字符串,一个字符串,一个字符串,不管它是否为空字符串。使用
equals()

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

更好,但可能会出现空指针异常。更好的是:

"".equals(s1)
没有空指针异常

编辑:好的,询问了这一点。本条将其定义为:

假设我们有一些对象集, 具有等价关系。A. 通过指定 S的某些对象是“规范的” “形式”,使每个对象 对价等于对价 一个标准形式的对象

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

3/2、6/4、24/16

rationalnumer通常是这样编写的: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(...) { ... }
}
无法直接实例化实例,因为构造函数是私有的。这只是一种工厂方法。工厂方法允许您执行以下操作:

  • 始终返回相同的实例(抽象单例)
  • 只需在每次通话中创建一个新的intsance
  • 以规范形式返回对象(稍后将详细介绍);或
  • 你喜欢什么都行
基本上,工厂方法抽象了对象创建,我个人认为强制所有构造函数都是私有的以强制使用此模式是一个有趣的语言特性,但我离题了

使用此factory方法可以缓存您创建的实例,以便对任意两个实例s1和s2执行以下测试:

(s1 == s2) == s1.equals(s2)
所以当我说字符串不是严格规范的时候,它意味着:

String s1 = "blah";
String s2 = "blah";
System.out.println(s1 == s2); // true
但正如其他人所指出的,您可以通过以下方式改变这一点:

String s3 = new String("blah");
还有可能:

String s4 = String.intern("blah");
所以你不能完全依赖于引用等式,所以你根本不应该依赖它

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

无论如何,这是标准形式

"".equals(s)

似乎是最好的选择,但Apache commons lang库中也包含了Stringutils.isEmpty
,这与您最初的问题有些不同,但始终存在

if(s1.length() == 0)
我相信这相当于1.6中的isEmpty()方法

给定两个字符串:

String s1 = "abc";
String s2 = "abc";
-或-

对两个对象执行的==运算符检查对象标识(如果两个运算符返回到同一个对象实例,则返回true。)应用于java.lang.Strings的==的实际行为并不总是一致的,因为字符串被替换

在Java中,字符串(至少部分由JVM决定)在任何时间点,s1和s2可能是或可能不是同一个对象引用(假设它们具有相同的值)。因此,
s1==s2
可能返回true,也可能不返回true,这完全取决于s1和s2是否都已被插入

使s1和s2等于空字符串对这一点没有影响-它们仍然可能被拘留,也可能没有被拘留


简而言之,如果s1和s2具有相同的内容,==可能返回true,也可能不返回true。s1.如果s1和s2的内容相同,则equals(s2)保证返回true。

使用,或者如果需要空检查。

简短回答

s1 == ""         // No!
s1.equals("")    // Ok
s1.isEmpty()     // Ok: fast (from Java 1.6) 
"".equals(s1)    // Ok: null safe
我保证s1不为null,并使用isEmpty()

注意:空字符串“”不是特殊字符串,但会计为任何其他“值”

再回答一点

s1 == ""         // No!
s1.equals("")    // Ok
s1.isEmpty()     // Ok: fast (from Java 1.6) 
"".equals(s1)    // Ok: null safe
对字符串对象的引用取决于它们的创建方式:

使用操作符new创建的字符串对象始终引用单独的对象,即使它们存储相同的字符序列,因此:

String s1 = new String("");
String s2 = new String("");
s1 == s2 // false
使用运算符=创建的字符串对象后跟用双引号括起来的值(=“value”)存储在字符串对象池中:在池中创建新对象之前,使用
String s1 = new String("abc");
String s2 = new String("abc");
s1 == ""         // No!
s1.equals("")    // Ok
s1.isEmpty()     // Ok: fast (from Java 1.6) 
"".equals(s1)    // Ok: null safe
String s1 = new String("");
String s2 = new String("");
s1 == s2 // false
String s1 = ""; // "" added to the pool
String s2 = ""; // found "" in the pool, s2 will reference the same object of s1
s1 == s2        // true
String s1 = "";  
s1 == "";        //true
s1.equals("");
"".equals(s1);