我关于Java对待的方式有点混乱==
和equals()
,当谈到int
, Integer
和其他类型的数字。 例如:
Integer X = 9000;
int x = 9000;
Short Y = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
// results.add(X == Y); DOES NOT COMPILE 1)
results.add(Y == 9000); // 2)
results.add(X == y); // 3)
results.add(X.equals(x)); // 4)
results.add(X.equals(Y)); // 5)
results.add(X.equals(y)); // 6)
System.out.println(results);
输出(也许你应该让你的猜测在前):
[true, true, true, false, false]
- 这
X == Y
不能编译是可以预料的,是不同的对象。 - 我有点惊讶,
Y == 9
是true
的,因为9是在默认情况下的int
,并考虑到1)甚至没有编译。 请注意,你不能把一个int
到期待的方法Short
,但在这里,他们是平等的。 - 这是令人惊讶出于同样的原因为两个,但似乎更糟糕。
- 并不奇怪,因为
x
是autoboxed并Integer
。 - 并不奇怪,因为在不同的类的对象不应该是
equal()
- 什么??
X == y
是true
,但X.equals(y)
是false
? 不宜==
总是比严格equals()
我会很感激,如果有人能帮助我理解这一点。 是什么原因做==和equals()这样的行为?
编辑:我已经改变了9至9000表明,这种行为是不相关的任何不寻常的方式,该整数从-128到127的行为。
第二编辑:OK,如果你认为你明白这东西,你应该考虑以下内容,只是为了确保:
Integer X = 9000;
Integer Z = 9000;
short y = 9000;
List<Boolean> results = new ArrayList<Boolean>();
results.add(X == Z); // 1)
results.add(X == y); // 2)
results.add(X.equals(Z)); // 3)
results.add(X.equals(y)); // 4)
System.out.println(results);
输出:
[false, true, true, false]
究其原因,作为最好的,我的理解是:
- 不同的实例,因此不同。
-
X
装箱,然后相同的值,所以相等。 - 相同的值,所以相等。
-
y
不能盒装到一个Integer
,从而可以不相等。
的原因
X == y
为真的有这样做的二进制数值提升。 当至少一个操作数的相等操作可以转换为一个数字类型, 数字相等运算被使用。 首先,第一个操作数拆箱。 然后,这两个操作数被转换为int
。
而
X.equals(y)
是一个普通的函数调用。 正如已经提到的, y
将autoboxed一个Short
的对象。 Integer.equals
如果参数不是总是返回false Integer
实例。 这可以通过检查落实情况很容易看到。
有人可能会说,这是一个设计缺陷。
(小)整数实例缓存,所以不变X == y的holded者为小实例(实际上-127 +128,取决于JVM):
Integer a = 10;
Integer b = 10;
assert(a == b); // ok, same instance reused
a = 1024;
b = 1024;
assert(a == b); // fail, not the same instance....
assert(a.equals(b)); // but same _value_
编辑
4)和5)产生错误的,因为equals
支票类型: X
是一个整数,而Y
是短。 这是java.lang.Integer中的#等于方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
这个故事的士气:
自动装箱/拆箱是混乱的,因为是类型提升。 总之,他们为好谜语,但可怕的代码。
在实践中,很少有意义的使用数值类型比INT小,我几乎倾向于配置我的Eclipse编译器标记所有自动装箱和-unboxing为错误。
在这里你的问题不仅是如何对待==但自动装箱......当你比较Y和9你比较了两个基本要素是平等的,在后两种情况下,你得到错误的,只是因为这是如何工作的相等。 两个对象是仅当它们是同一种,并具有相同的值相等。 当您在“X.equals(Y)”你告诉它做Integer.equals(短),看着Integer.equals(实行说),它会失败:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
由于自动装箱的最后两个将导致相同的故障,因为它们都将被传入的短裤。
编辑:忘了一件事......在results.add的情况下(X == Y); 它将拆箱X和做(X.intValue()== y)的这恰好是真以及9 == 9
我记得重写“等于(obj对象)”一个好的做法是首先检查传入的参数的类型 。所以perhap这将导致X.equals(Y)是假的 。 您可能要检查的烃源代码,以挖出真相:)
如何自动装箱工作以及如何稍微详细的“小”有价值的Integer对象缓存:
当一个原始int值autoboxed成一个整数,所述编译器通过与到Integer.valueOf(...)的调用替代代码。 因此,以下内容:
Integer a = 10;
被替换通过与以下的编译器:
Integer a = Integer.valueOf(10);
调用valueOf(...)Integer类的方法维护一个包含-127和128之间的所有值Integer对象如果与在这一范围内的值调用的valueOf(...),该方法返回一个预先缓存从缓存中存在的对象。 如果该值在该范围之外,则返回与指定的值进行初始化一个新的整数对象。 (如果你想知道它究竟是如何工作的,查找文件src.zip在JDK安装目录,并查找类java.lang.Integer在它的源代码。)
现在,如果你这样做:
Integer a = 10;
Integer b = 10;
System.out.println(a == b);
你会看到打印, 真正的 -但并不是因为A和B具有相同的价值,但由于A和B是指相同的Integer对象,从Integer.valueOf(...)返回缓存中的对象。
如果您更改值:
Integer a = 200;
Integer b = 200;
System.out.println(a == b);
然后假是印刷的,因为200是高速缓存的范围外,因此A和B指的是两个不同的整数对象。
这是不幸的==用于值类型对象的平等,如包装类和字符串在Java中 - 这是违反直觉的。
Java将在需要时一个Integer自动转换成一个int。 同样适用于短。 此功能称为自动装箱和autounboxing。 你可以阅读一下这里 。
这意味着,当您运行的代码:
int a = 5;
Integer b = a;
System.out.println(a == b);
Java的将其转换为:
int a = 5;
Integer b = new Integer(a);
System.out.println(a == b.valueOf());