JAVA中关于相等运算符(兼容操作数)的查询

Posted

技术标签:

【中文标题】JAVA中关于相等运算符(兼容操作数)的查询【英文标题】:Query regarding equality operator(compatible operands) in JAVA 【发布时间】:2014-10-27 16:15:26 【问题描述】:

我是 JAVA 新手,正在使用相等运算符。在尝试了几种操作数组合之后,我对 Java 中相等运算符(==)的兼容操作数的确切定义有点困惑。

int x = 23;
if (x == 23.3f)    // compiler accepts it. (may be because both are primitives)

int x = 23;     
Double d = new Double(23.3); 
if (x == d)     // compiler accepts it. (may be compatible pair of primitive and object reference)

int x = 23;
String s = "hello";
if (x == s)   // compiler throws error  - incompatible operands for == operator.

所以,在我看来,相等运算符的兼容操作数应该有一些正式的定义。请帮助我澄清这个疑问。

【问题讨论】:

对于字符串有.equals 方法。在您的最后一个if 中,很明显它们是不兼容的,因为您试图将 Object(String) 与原始类型 (int,long,double ...) 进行比较 我知道 .equals 存在,但我的查询专门针对 ==。如果您看到我的第二个示例,我将原始与 Object(Double.) 进行比较,编译器接受它。 【参考方案1】:

对于

int x = 23;
if (x == 23.3f) 

如果您使用javap -v 查看字节码,int 将转换为float。即,将调用i2f,然后使用fcmpl将它们作为2个浮点值进行比较。

public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   bipush  23
   2:   istore_1
   3:   iload_1
   4:   i2f       // The line of interest. Converts int to float.
   5:   ldc     #16; //float 23.3f
   7:   fcmpl     // compare two floats
   8:   ifne    11
   11:  return

在第三种情况下,您正在将一个基元与一个对象(字符串)进行比较,这是不可能的。

【讨论】:

【参考方案2】:

    编译器接受它,因为 x23.3f 具有原始数字类型。比较会返回false

    编译器接受它,因为 java unboxes Double 对象与 double 原语进行比较。

    编译器无法接受它,因为x 是原始数字类型,而s 是对String 类实例的引用。无法比较数字原语和对对象的引用。

【讨论】:

关于#2,拆箱总是在您的其他操作数是原始操作数时发生? 根据官方定义:Autoboxing (and unboxing) is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes.原始类型和对应的对象包装类示例:intIntegerdoubleDouble等。比较如果一个操作数是包装类实例和其他操作数是原始类型,然后进行拆箱。此外,如果两个操作数都是包装类实例,即 Integer,那么 java 会比较这些对象的值,而不是引用。 若要比较 Double 和/或 double 值,请勿使用 == 运算符。使用java.lang.Double.compare() 方法。这是因为精度问题。检查此链接,例如:tutorialspoint.com/java/lang/double_compare.htm 我也建议您避免使用。 2. 就我而言,我永远不记得是对原始对象进行装箱还是对对象进行拆箱,两种情况下的结果都不一样。因此,为了便于阅读,如果这是您想要的,请明确取消装箱,如 x == d.doubleValue()(不过,我也同意警告不要将双精度值与 == 进行比较)。【参考方案3】:

字符串是对象。 == 通过引用而不是内部值来比较对象。 所有其他(int, double)== 中通过对象引用进行比较,因此如果字符串不匹配,因此对于字符串,我们必须使用.equals 运算符,java 也是区分大小写的,因此在比较字符串时,您必须注意Case's of strings

【讨论】:

【参考方案4】:

等式运算符意味着一些限制和转换,规则相当大,在语言规范https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.21中有描述

    所以在第一种情况下,“x”在比较之前提升为浮点类型。 在第二个“d”中拆箱,“x”在比较之前提升为双精度类型。 在第三个编译时出现错误,因为 String 与原始类型不兼容。 String 可以与继承它的相同类型或类型进行比较。

编译时错误也可能发生,因为类类型不相关(也就是说,它们不一样,也不是另一个的子类),所以它们之间的转换总是会失败。 关于类型与某个接口类型的比较,编译器允许任何比较,除非一个变量永远不能引用实现该接口的值,这是因为类型是最终类型,而最终类型的变量总是持有与其编译时类型相同的运行时类型的值。因此,变量的运行时类型必须是没有实现指定接口的类型。

【讨论】:

以上是关于JAVA中关于相等运算符(兼容操作数)的查询的主要内容,如果未能解决你的问题,请参考以下文章

检测到类型不兼容的二元运算符。找到类型相等的操作数类型 edm.string 和 edm.guid

无法在 SQL 数据工具脚本中应用相等“运算符 '==' 不能应用于 'bool' 类型的操作数” (FIX)

为啥相等运算符适用于整数值,直到 128 数字? [复制]

Java 关系运算符

Python中关于日期相等的GQL查询

Linq 动态查询问题 - 运算符“或”与操作数类型“布尔”和“字符串”不兼容