使用==检查对象引用相等(在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的情况)。
这意味着,为了“比较”两种引用类型,应该能够将其转换为另一种引用类型。 字符串“是”一个对象,但String
和StringBuilder
之间没有“强制转换”。
编译器试图帮助您。
当因为类型冲突而导致==
永远不可能时,它会假定您犯了一个错误,并拒绝编译代码。
也可以使用instanceof
,也可以使用强制转换。
String a = null; if (a instanceof StringBuilder){} // compile-error StringBuilder b = (StringBuilder) a; // compile-error
因为, String
是一个Object
但String
不是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
。
String
与Object
兼容,因此将引用与这些类型进行比较不是编译时错误。 StringBuilder
与Object
兼容,因此您可以将StringBuilder
分配给Object
-typed变量。 但String
和StringBuilder
彼此不兼容。 因此,如果您有String
引用和Object
引用,则可以在没有编译时错误的情况下对它们进行比较。 但是如果你有一个String
引用和一个StringBuilder
引用,你就不能 – 编译器知道比较永远不会true
。
注意它是如何关于引用的类型(变量),而不是分配给它们的对象的类型。 这就是为什么它可以设置你的第二个场景并让它编译,即使它永远不会有真正的结果。