我有一个关于在Java中将字符串与空字符串进行比较的问题.有没有区别,如果我将字符串与空字符串比较==
或equals
?例如:
String s1 = "hi"; if (s1 == "")
要么
if (s1.equals(""))
我知道应该比较字符串(和一般的对象)equals
,而不是==
,但我想知道它是否对空字符串很重要.
s1 == ""
是不可靠的,因为它测试引用相等而不是对象相等(并且String不是严格的规范).
s1.equals("")
更好,但可能会遇到空指针异常.更好的是:
"".equals(s1)
没有空指针异常.
编辑:好的,关于规范形式的问题.本文将其定义为:
假设我们有一些S对象,具有等价关系.通过将S的某些对象指定为"规范形式"来给出规范形式,使得所考虑的每个对象恰好等同于规范形式的一个对象.
给你一个实际的例子:取一组有理数(或"分数",它们通常被称为).有理数由分子和denomoinator(除数)组成,两者都是整数.这些有理数字是等价的:
3/2,5/4,24/16
通常编写Rational 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(...) { ... } }
实例无法直接实例化,因为构造函数是私有的.这只是一种工厂方法.工厂方法允许您做的是:
总是返回相同的实例(抽象的单例);
只需在每次通话时创建一个新的intsance;
以规范形式返回对象(在一秒钟内更多关于此); 要么
随你喜欢.
基本上工厂方法抽象对象创建,我个人认为这将是一个有趣的语言功能,强制所有构造函数是私有的,以强制使用这种模式,但我离题.
使用此工厂方法可以执行的操作是缓存您创建的实例,以便对于任何两个实例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()方法来解决它.但这很棘手.类加载器也会影响这个问题.
无论如何,这是规范的形式.
这将取决于字符串是否是文字.如果使用创建字符串
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()
这与你原来的问题有些不同,但总会如此
if(s1.length() == 0)
我相信这相当于1.6中的isEmpty()方法.
"".equals(s)
似乎是最好的选择,但是Stringutils.isEmpty(s)
Apache commons lang库中也包含了这个选项
简短的回答
s1 == "" // No! s1.equals("") // Ok s1.isEmpty() // Ok: fast (from Java 1.6) "".equals(s1) // Ok: null safe
我保证s1不为null并使用isEmpty().
注意:空字符串""不是特殊字符串,而是计为任何其他"值".
再问一点
对String对象的引用取决于它们的创建方式:
使用new new运算符创建的String对象总是引用单独的对象,即使它们存储相同的字符序列,所以:
String s1 = new String(""); String s2 = new String(""); s1 == s2 // false
使用operator =后跟一个包含在双引号(="value")中的值的字符串对象存储在String对象池中:在池中创建新对象之前,在池中搜索具有相同值的对象如果找到则引用.
String s1 = ""; // "" added to the pool String s2 = ""; // found "" in the pool, s2 will reference the same object of s1 s1 == s2 // true
对于使用双引号("value")包含值的字符串创建的字符串也是如此,因此:
String s1 = ""; s1 == ""; //true
字符串等于对两者的方法检查,这就是为什么它可以安全地编写:
s1.equals("");
如果s1 == null,则此表达式可能抛出NullPointerException,因此,如果之前未检查null,则编写更安全:
"".equals(s1);
请阅读我如何比较Java中的字符串?
希望它可能有助于没有经验丰富的用户,他们可能会发现其他答案有点过于复杂.:)
字符串,是一个字符串,是一个字符串,无论它是否为空字符串.使用equals()
.