使用==检查对象引用相等(在Java中)

为什么…

String a = new String("a"); StringBuilder b = new StringBuilder("a"); System.out.println(a==b); 

…在编译时会导致类型不兼容的错误…

  String a = new String("b"); Object b = new StringBuilder("b"); System.out.println(a==b); 

… 才不是?

为什么我可以比较String和Object的对象引用,但不能比较StringBuilder和String? 它们不仅仅是内存位置的地址吗?

谢谢

根据Java语言规范(15.21.3):

如果无法通过强制转换(§5.5)将任一操作数的类型转换为另一个操作数的类型,则这是一个编译时错误。 两个操作数的运行时值必然是不相等的(忽略两个值都为null的情况)。

这意味着,为了“比较”两种引用类型,应该能够将其转换为另一种引用类型。 字符串“是”一个对象,但StringStringBuilder之间没有“强制转换”。

编译器试图帮助您。

当因为类型冲突而导致==永远不可能时,它会假定您犯了一个错误,并拒绝编译代码。

也可以使用instanceof ,也可以使用强制转换。

 String a = null; if (a instanceof StringBuilder){} // compile-error StringBuilder b = (StringBuilder) a; // compile-error 

因为, String是一个ObjectString不是StringBuilder 。 您可以使用==在相同类型和超类型上比较引用。 请看下面的例子

 class A{ } class B extends A{ } class C{ } 

现在,

  A a =new A(); A b =new B(); // or B b =new B(); C c= new C(); System.out.println(a==b); // It is ok System.out.println(a==c); // It will generate compile time error 

String像任何其他类一样扩展Object类型,但不inheritanceStringBuilder 。 因此,在您的比较中, String回退到Object ,它们一个共同的类型。

因为Strings和StringBuilders都是Object类的子类。 但它们不是同一类,因此无法使用==进行比较。 您需要在StringBuilder上调用toString方法。

在第二个示例中,String也是一个Object,因为所有类都是Object的子类,您可以检查它们是否为==。

在第一个示例中,您将String与StringBuilder进行比较,它们是不同的类,并且都不是另一个的子类,因此运算符失败。

因为您必须比较兼容类型 ,因为比较不兼容类型的相等性将始终为false

StringObject兼容,因此将引用与这些类型进行比较不是编译时错误。 StringBuilderObject兼容,因此您可以将StringBuilder分配给Object -typed变量。 但StringStringBuilder彼此不兼容。 因此,如果您有String引用和Object引用,则可以在没有编译时错误的情况下对它们进行比较。 但是如果你有一个String引用和一个StringBuilder引用,你就不能 – 编译器知道比较永远不会true

注意它是如何关于引用的类型(变量),而不是分配给它们的对象的类型。 这就是为什么它可以设置你的第二个场景并让它编译,即使它永远不会有真正的结果。