当""== s为假但"".equals(s)为真时

Osc*_*Ryz 33 java comparison equality equals

编辑 感谢您的快速回复.请看看真正的问题是什么.这次我大胆了.

我理解==和.equals之间的区别.所以,这不是我的问题(我实际上添加了一些上下文)


我正在为空字符串执行以下验证:

if( "" == value ) { 
    // is empty string 
} 
Run Code Online (Sandbox Code Playgroud)

过去从db中获取值或从另一个节点反序列化对象时,此测试失败,因为两个字符串实例确实是不同的对象引用,尽管它们包含相同的数据.

所以这些情况的解决方案是

if( "".equals( value ) ) {
   // which returns true for all the empty strings
}
Run Code Online (Sandbox Code Playgroud)

我很好.这很清楚.

今天这又发生了一次,但它让我感到困惑,因为这次应用程序是一个非常小的独立应用程序,根本不使用网络,所以没有从数据库中提取新字符串,也不从另一个节点去激活.

所以问题是:


其他情况下:

"" == value // yields false 
Run Code Online (Sandbox Code Playgroud)

"".equals( value ) // yields true
Run Code Online (Sandbox Code Playgroud)

对于本地独立应用程序?

我很确定代码中没有使用新的String().

并且字符串引用可以是""的唯一方法是因为它直接在代码中分配""(或者我认为的那样),如:

String a = "";
String b = a;

assert "" == b ; // this is true 
Run Code Online (Sandbox Code Playgroud)

不知何故(在阅读完代码之后,我有一个线索)创建了两个不同的空字符串对象引用,我想知道如何

更多关于jjnguys的回答:

字节!

编辑:结论

我找到了原因.

在jjnguy建议之后,我能够以不同的眼光看待代码.

有罪的方法:StringBuilder.toString()

分配并初始化一个新的String对象,以包含此对象当前表示的字符序列.

卫生署!...

    StringBuilder b = new StringBuilder("h");
    b.deleteCharAt( 0 );
    System.out.println( "" == b.toString() ); // prints false
Run Code Online (Sandbox Code Playgroud)

谜团已揭开.

该代码使用StringBuilder来处理不断增长的字符串.事实证明,在某些时候有人做了:

 public void someAction( String string ) { 
      if( "" == string ) {
           return;
       }

       deleteBankAccount( string );
 }
Run Code Online (Sandbox Code Playgroud)

并使用

 someAction( myBuilder.toString() ); // bug introduced. 
Run Code Online (Sandbox Code Playgroud)

ps我最近读过太多CodingHorror吗?或者为什么我觉得有必要在这里添加一些有趣的动物图片?

jjn*_*guy 26

String s = "";
String s2 = someUserInputVariale.toLowercase(); // where the user entered in ""
Run Code Online (Sandbox Code Playgroud)

这样的事情会导致s == s2评估为假.

很多代码都会创建新代码,Strings而不会将调用暴露给new String().

  • 不,我喜欢它."我们Java程序员甚至都不知道如何SPELL优化......优点......看,JIT为我们做好了吗?" (12认同)

Bil*_*ard 21

"" == value // yields false
Run Code Online (Sandbox Code Playgroud)

"".equals( value ) // yields true
Run Code Online (Sandbox Code Playgroud)

任何时候变量的值value都没有被实现.如果在运行时计算该值,则会出现这种情况.有关说明此内容的示例代码,请参阅JLS部分3.10.5字符串文字:

因此,测试程序由编译单元组成(第7.3节):

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}
class Other { static String hello = "Hello"; }
Run Code Online (Sandbox Code Playgroud)

和编译单位:

package other;
public class Other { static String hello = "Hello"; }
Run Code Online (Sandbox Code Playgroud)

产生输出:

true true true true false true
Run Code Online (Sandbox Code Playgroud)

这个例子说明了六点:

  • 同一个包(第7节)中同一个类(第8节)中的文字字符串表示对同一个String对象的引用(第4.3.1节).
  • 同一个包中不同类中的文字字符串表示对同一String对象的引用.
  • 不同包中不同类中的文字字符串同样表示对同一String对象的引用.
  • 由常量表达式计算的字符串(第15.28节)在编译时计算,然后将其视为文字.
  • 在运行时计算的字符串是新创建的,因此是不同的.
  • 显式实现计算字符串的结果与具有相同内容的任何预先存在的文字字符串的字符串相同.


Tom*_*Tom 10

如果你能抓住Joshua Bloch和Neal Gafter的Java Puzzlers这本书,看一下拼图13,"动物农场"......他对这个问题有很好的建议.我要复制一些相关的文字:

"你可能知道类型的那个编译时常String拘留 [JLS 15.28]换句话说任意两个常量表达式类型的String用于指定相同的字符序列是由相同的对象引用表示... 您的代码应该很少,如果有的话,依赖于字符串常量的实习.实习的目的只是为了减少虚拟机的内存占用,不作为程序员的工具......当比较对象引用,你应该使用equals优先方法的==操作,除非你需要比较对象身份而不是价值."

这是我在上面提到的参考资料......在我的书中的第30-31页.

  • 换句话说......使用等于因为它就是你的意思......这就是你的意思. (2认同)

djn*_*jna 7

你期望"abcde".substring(1,2)"zbcdefgh".substring(1,2)产生相同的String对象吗?

它们都产生从两个不同字符串中提取的"相等"子字符串,但是tehy是不同的对象似乎很合理,因此==将它们视为不同.

现在考虑子串的长度为0 , substring(1, 1). 它产生一个零长度的String,但是它与"abcde".substring(1,1)另一个对象并不奇怪,"zbcdefgh".substring(1,2)因此它们中的至少一个是与""不同的对象.

  • 我做.它说,即使没有显式调用"new String",很多代码仍然会创建新的字符串...... substring,toUpperCase等. (2认同)