Java 什么时候"E;==s是假的,但是&引用;。equals(s)是真的

Java 什么时候"E;==s是假的,但是&引用;。equals(s)是真的,java,comparison,equals,equality,Java,Comparison,Equals,Equality,编辑 谢谢你的及时回复。请看看真正的问题是什么。这次我大胆了 我确实理解==和.equals之间的区别。所以,这不是我的问题(我实际上添加了一些上下文) 我正在对空字符串执行以下验证: if( "" == value ) { // is empty string } 在过去的中当从数据库获取值或从另一个节点反序列化对象时,此测试失败,因为两个字符串实例确实是不同的对象引用,尽管它们包含相同的数据 因此,解决这些情况的办法是 if( "".equals( value ) ) {

编辑 谢谢你的及时回复。请看看真正的问题是什么。这次我大胆了

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


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

if( "" == value ) { 
    // is empty string 
} 
在过去的当从数据库获取值或从另一个节点反序列化对象时,此测试失败,因为两个字符串实例确实是不同的对象引用,尽管它们包含相同的数据

因此,解决这些情况的办法是

if( "".equals( value ) ) {
   // which returns true for all the empty strings
}
我同意。这很清楚

今天,这种情况再次发生,但它让我感到困惑,因为这次应用程序是一个非常小的独立应用程序,根本不使用网络,因此不会从数据库中提取新字符串,也不会从另一个节点反序列化

因此,问题是:


其他情况下: 及

对于本地独立应用程序

我很确定代码中没有使用新字符串()

字符串引用可以是“”的唯一方式是因为它直接在代码中被赋值“”(或者我是这么认为的),如:

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

更多关于JJN的回答:

字节

编辑:结论

我找到了原因

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

有罪的方法:StringBuilder.toString()

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

    StringBuilder b = new StringBuilder("h");
    b.deleteCharAt( 0 );
    System.out.println( "" == b.toString() ); // prints false
谜团解开了

代码使用StringBuilder处理不断增长的字符串。事实证明,在某个时刻,有人做到了:

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

       deleteBankAccount( string );
 }
和使用

 someAction( myBuilder.toString() ); // bug introduced. 
p、 我最近读了太多的书了吗?或者为什么我觉得有必要在这里添加一些有趣的动物图片

String s = "";
String s2 = someUserInputVariale.toLowercase(); // where the user entered in ""
类似的情况会导致
s==s2
的计算结果为false


许多代码都会创建新的
字符串
而不公开对
新字符串()的调用
您应该尝试考虑
字符串.length()==0
您是否希望
子字符串(1,2)
子字符串(1,2)
生成相同的字符串对象

它们都从两个不同的字符串中提取出“相等”的子字符串,但是它们是不同的对象,所以==认为它们是不同的,这似乎是很合理的

现在考虑子串的长度为0、<代码>子串(1, 1)< /代码>。它产生一个零长度的字符串,但毫不奇怪,

“abcde”。子字符串(1,1)
“zbcdefgh”是不同的对象。子字符串(1,2)
,因此至少有一个是与“.”不同的对象。

为什么不使用:

if (value != null && value.length == 0) {
    // do stuff (above could be "== null ||"
}

您应该使用
equals()
,因为对象的
==
比较引用,即它们是同一个对象。虽然Java在编译时发现相同的字符串并使它们共享相同的引用(字符串是不可变的),但在运行时很容易创建具有不同引用的空字符串,其中==对于
equals()的典型意图是失败的

据我所知,在将Java代码编译为字节码或运行程序时,在大多数情况下,相同的字符串将引用到相同的对象以节省内存。因此,有时您可以对字符串进行==比较。但这是一个编译器优化你不能依赖

但有时编译器决定不进行这种优化,或者程序无法看到字符串是相同的,并且检查突然失败,因为您依赖于一些底层优化巫术,这取决于您正在使用的jvm的实现,等等


所以使用equals总是一件好事。对于空字符串,还有其他的可能性,比如与length==0进行比较,或者如果您不关心向后兼容性,则存在string.empty()

检查此参考:在最佳位置。值得一个书签。

如果你能抓住约书亚·布洛赫和尼尔·加夫特的《Java拼图者》一书,看看拼图13,“动物农场”。。。他在这个问题上有很好的建议。我将复制一些相关文本:

“您可能知道,
String
类型的编译时常量是插入的[JLS 15.28]。换句话说,指定相同字符序列的任何两个
String
类型的常量表达式都由相同的对象引用表示…您的代码应该很少(如果有的话)依赖于字符串常量的内部调用。内部调用仅用于减少虚拟机的内存占用,not作为程序员的工具……在比较对象引用时,应优先使用
==
方法,而不是
=
运算符,除非需要比较对象标识而不是值。”

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

"" == value // yields false

变量
的值未插入的任何时间。如果在运行时计算该值,则会出现这种情况。请参见示例代码以说明这一点:

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

及编制组:

package other;
public class Other { static String hello = "Hello"; }
生成输出:

true true true true false true
这个例子说明了六点:

  • 同一包(§7)中同一类(§8)中的文字字符串表示对同一字符串对象(§4.3.1)的引用
  • 文学
    "" == value // yields false
    
    "".equals( value ) // yields true
    
    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"; }
    
    package other;
    public class Other { static String hello = "Hello"; }
    
    true true true true false true