toString(),==,equals()对象方法在引用和基元类型上的工作方式有何不同或类似?
toString()
方法, ==
运算符和equals()
方法如何在引用和基元类型上以不同或相似的方式工作?
对于常规类型(包括String):
-
==
比较对象引用。 它测试两个对象引用是否相等; 即如果他们引用同一个对象。 -
equals(Object)
测试此对象是否“等于”另一个对象。 “等于”的含义取决于对象的类如何定义相等性。java.lang.Object
类将equals(other)
定义为this == other
,但许多类重写此定义。 -
toString()
提供了对象到String的简单转换。 结果String的格式和内容是特定于类的,并且(从java.lang.Object
契约的角度来看)不能保证它有意义。
对于(真)原始类型:
-
==
比较类型的值,和 - 未定义
equals()
和toString()
。 Java不允许您在原始值上调用方法。
然而,由于在某些情况下 Java语言表示原始类型可以“自动装箱”以给出基本类型的相应包装类型的实例,因此这很复杂。 例如, int
对应于java.lang.Integer
,依此类推。 对于包装类:
-
==
的定义与任何其他引用类型相同, -
equals()
比较包装的值,和 -
toString()
格式化包装的值。
工程中的扳手如下图所示:
int a = ... int b = a; Integer aa = a; // autoboxing occurs Integer bb = b; // autoboxing occurs assert a == b; // always succeeds assert aa.equals(bb); // always succeeds assert aa == bb; // sometimes succeeds, sometimes fails.
最后一次失败的原因是JLS不保证给定原始值的自动装箱将始终给出相同的包装器对象。 在某些情况下(例如对于小整数),对于其他情况(例如大整数)则不会。
从上面的示例中学到的教训是,在引用类型上使用==
时需要非常小心。 只有当你真的要测试两个引用是否属于同一个对象时才使用它。 如果您只想测试对象是否“相等”而没有调用equals()
的开销,请不要使用它。
(另请注意, String
是另一种类型,其中==
在许多情况下会给你错误的答案;请参阅如何比较Java中的字符串? )
对于引用类型,==将比较实际引用(对象所在的内存位置),其中equals方法执行数据比较。
出于性能原因,JVM有时会“字符串实例化”您的不可变字符串。 导致这种情况:
String a = "abc"; String b = "abc"; if (a == b){ //The if statement will evaluate to true, //if your JVM string interns a and b, //otherwise, it evaluates to false. }
‘==’运算符适用于您具有的基本类型,在引用对象的情况下,它是引用本身。 这是a == b
会将原始类型的值作为int进行比较,但会比较引用类型的引用(而不是值)。 两个引用类型不同但具有相同值的对象将在调用equals()
方法时返回true
,但a == b
将为false。
对于基本类型,在调用方法时,先将类型转换(加框)为引用类型,然后调用该方法。 这意味着对于基本类型, a == b
将产生与a.equals(b)
相同的值,但在后一种情况下,在调用equals()
方法之前会创建两个临时的盒装对象。 这将使CPU操作中的操作更加昂贵,这可能是也可能不是问题,这取决于它发生的位置。
也就是说,要比较基本类型值,您应该使用==
,而要比较引用类型值,您应该使用.equals()
方法。
toString()
方法也是如此。 在引用类型对象上调用时,它将调用适当的方法并生成一个String。 当调用基本类型时,类型将被自动装箱,然后将在临时对象中调用该方法。 在这种情况下,您可以调用相应的toString()
静态方法(即对于int调用Integer.toString( myint )
),这将避免创建临时对象。