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】:编译器接受它,因为 x
和 23.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.
原始类型和对应的对象包装类示例:int
和Integer
、double
和Double
等。比较如果一个操作数是包装类实例和其他操作数是原始类型,然后进行拆箱。此外,如果两个操作数都是包装类实例,即 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