当谈到==
,equals()
和其他类型的数字时,我对Java处理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
已自动退回到Integer
。equal()
。X == y
是true
但X.equals(y)
是false
? ==
不应该比equals()
更严格吗?如果有人能帮助我理解这一点,我会很感激。出于什么原因,==和equals()会以这种方式运行?
编辑:我已将9更改为9000,以表明此行为与-128到127之间的整数行为的任何异常方式无关。
2 nd 编辑:好的,如果你认为你理解这些东西,你应该考虑以下几点,只是为了确保:
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
,因此不能相等。答案 0 :(得分:21)
(小)整数实例被缓存,因此对于小实例(实际-127 +128,取决于JVM),不变的x == y被保留:
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#equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
答案 1 :(得分:11)
原因
X == y
为true与binary numeric promotion.有关当等于运算符的至少一个操作数可转换为数字类型时,使用numeric equality operator。首先,第一个操作数是未装箱的。然后,两个操作数都转换为int
。
虽然
X.equals(y)
是正常的函数调用。如上所述,y
将自动装箱到Short
个对象。如果参数不是Integer.equals
实例,Integer
总是返回false。通过检查实现可以很容易地看出这一点。
有人可能会说这是一个设计缺陷。
答案 2 :(得分:6)
故事的士气:
自动装箱/拆箱令人困惑,类型促销也是如此。他们共同创造了好的谜语,但却是可怕的代码。
实际上,使用小于int的数字类型很少有意义,而且我几乎倾向于配置我的eclipse编译器将所有自动装箱和-unboxing标记为错误。
答案 3 :(得分:3)
你的问题不仅仅是它如何对待==而是自动装箱......当你比较Y和9时,你正在比较两个相等的基元,在最后两种情况下你会得到假,因为这是等于工作的。只有两个对象具有相同的类型且具有相同的值时,它们才相等。 当您在“X.equals(y)”中说出你做Integer.equals(Short)并查看Integer.equals()的实现时它会失败:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
由于自动装箱,最后两个会导致同样的失败,因为它们都会作为短裤传递。
编辑:忘了一件事......在results.add(X == y)的情况下;它将unbox X和do(X.intValue()== y)恰好是真的以及9 == 9
答案 4 :(得分:1)
如果需要,Java会自动将Integer转换为int。同样适用于Short。此功能称为自动装箱和自动装箱。你可以阅读它here。
这意味着当您运行代码时:
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());
答案 5 :(得分:1)
此自动转换称为自动装箱。
答案 6 :(得分:1)
我记得覆盖“equal(object obj)”的一个好习惯是首先检查传入的参数的类型。所以perhap这会导致 X.equals(Y)< / strong>要 false 。您可以查看源代码以挖掘真相:)
答案 7 :(得分:1)
关于自动装箱如何工作以及如何缓存“小”值Integer对象的更多细节:
当原始int被自动装入Integer时,编译器会通过调用Integer.valueOf(...)替换代码来完成此操作。所以,以下内容:
Integer a = 10;
由编译器替换为:
Integer a = Integer.valueOf(10);
类Integer的valueOf(...)方法维护一个缓存,该缓存包含介于-127和128之间的所有值的Integer对象。如果使用此范围内的值调用valueOf(...),则该方法返回缓存中预先存在的对象。如果该值超出范围,则返回使用指定值初始化的新Integer对象。 (如果您想确切知道它是如何工作的,请在JDK安装目录中查找文件 src.zip ,并在其中查找类java.lang.Integer的源代码。)
现在,如果你这样做:
Integer a = 10;
Integer b = 10;
System.out.println(a == b);
你会看到 true 被打印 - 但是不是因为a和b具有相同的值,但是因为a和b指的是同一个Integer对象, Integer.valueOf(...)返回的缓存中的对象。
如果更改值:
Integer a = 200;
Integer b = 200;
System.out.println(a == b);
然后打印 false ,因为200超出了缓存的范围,所以a和b引用了两个不同的Integer对象。
不幸的是,==用于值类型的对象相等,例如包装类和Java中的String - 这是违反直觉的。