使用"=="比较整数有什么作用?

11

编辑:好的,好的,我读错了。我没有将int与Integer进行比较。注意到了。

我的SCJP书上写道:

 

当==用于将原始类型与包装器对象进行比较时,包装器对象会被解包,然后进行原始类型之间的比较。

所以你可能认为这段代码会打印出true

    Integer i1 = 1; //if this were int it'd be correct and behave as the book says.
    Integer i2 = new Integer(1);
    System.out.println(i1 == i2);

但输出结果却是false

根据我的书籍,它应该打印true

Integer i1 = 1000; //it does print `true` with i1 = 1000, but not i1 = 1, and one of the answers explained why.
Integer i2 = 1000;
System.out.println(i1 != i2);

不是的。它是false

怎么回事?


看,我不确定书中的这部分是写得不好还是我太蠢了,但我就是看不懂它在说什么。我最好的理解是 == 与 != 的处理方式不同。也许 == 反映了值相等(深度相等),但 != 却不是这样。无论如何,书中所说的在现实生活中都不会发生。 - Bad Request
不,这种情况的问题在于你正在比较的两种类型。== 和 != 的行为方式是相同的。 - EboMike
仅凭这个例子,我就觉得Java不是一种真正的编程语言,而是某种恶作剧。 - dsimcha
3
@dsimcha - 这是一个十分无聊的说法。如果你比较两个整数指针,在C语言中同样可能会遇到相同的问题-只不过更加直接明了。 - EboMike
1
你的第二个例子确实打印出了 true。在 ideone 上可以看到。 - NullUserException
装箱很有用且安全,拆箱则不是。在使用这些表达式时,始终要注意数据类型。 - irreputable
7个回答

12

注意,较新版本的Java会缓存在-128到127范围内(256个值)的Integer,这意味着:

Integer i1, i2;

i1 = 127;
i2 = 127;
System.out.println(i1 == i2);

i1 = 128;
i2 = 128;
System.out.println(i1 == i2);

会输出truefalse。(在ideone上查看)

教训:为避免问题,比较两个对象时始终使用.equals()

当你用==比较一个包装过的基本类型和一个原始类型(例如:使用Integerint比较),你可以依赖于拆箱机制,但如果你比较两个Integer时使用==,那将失败,原因如@dan04所述。


有趣!我在现实生活中从未使用过==,但这是一场非常虐心的考试 :) - Bad Request
1
返回翻译文本:+1 对于非常相关的观点。我会挑剔并指出它是[-128到127](http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.7),尽管随附Sun JDK的1.6源代码显示它们与上限玩游戏(但它始终至少为127)。 - Tim Stone

8
Integer i1 = 1;
Integer i2 = new Integer(1);
System.out.println(i1 == i2);

当你给i1赋值为1时,这个值会被装箱成一个Integer对象。然后进行比较的是两个对象的引用。由于引用不相等,所以比较失败。
Integer i1 = 100;
Integer i2 = 100;
System.out.println(i1 != i2);

由于这些是使用编译时常量进行初始化的,编译器可以并且确实对它们进行内部化,并使两者指向同一个Integer对象。

(请注意,我将值从1000更改为100。正如@NullUserException所指出的那样,只有小整数会被内部化。)


这是一个非常有趣的测试。看看你能否弄清楚这个问题。为什么第一个程序打印true,但第二个程序打印false?利用你对装箱和编译时分析的知识,你应该能够解决这个问题:

// Prints "true".
int i1 = 1;
Integer i2 = new Integer(i1);
System.out.println(i1 == i2);

// Prints "false".
int i1 = 0;
Integer i2 = new Integer(i1);
i1 += 1;
System.out.println(i1 == i2);

如果您理解上述内容,请尝试预测此程序将打印什么:

如果你理解了上面的内容,试着预测一下这个程序会输出什么:

int i1 = 0;
i1 += 1;
Integer i2 = new Integer(i1);
System.out.println(i1 == i2);

(你猜测后,运行它并查看!

这很重要,因为只有小整数才会被内部化。请记住,Integer仅在执行valueOf调用时使用内部缓存(对于这些小值),编译器仍会生成两行invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer; - Tim Stone

6
你没有比较原始类型和包装器。你正在比较两个包装器(引用类型)。"==" 比较对象身份,因为它们是不同的对象,所以返回 false。

并非总是如此,较小的整数值被缓存,就像您调用Integer.valueOf一样。因此,实际上您正在比较相同的对象。 - bvdb

1

不,我不会认为代码打印true,并且您恰好回答了自己的原因。

当使用==比较基元和包装器时,包装器将被解包并将原语与原语进行比较。

然后您继续比较了两个Integer引用-也就是说,它比较了i1和i2的内存地址。您希望要么:

Integer i1 = 1;
Integer i2 = new Integer(1);
System.out.println(i1.equals(i2));

或者

int i1 = 1;
Integer i2 = new Integer(1);
System.out.println(i1 == i2);

1
请注意,您误读了您引用的摘录。该摘录特别将其语句限制为像这样的比较:
int k = 1;
Integer l = new Integer(1);
System.out.println(l == k);

0
自Java 5.0以来,有自动装箱和拆箱的功能,这意味着包装类可以隐式地转换为基本类型,反之亦然。但是,如果您比较两个整数对象,则仍在比较两个引用,并且没有任何触发自动装箱/拆箱的东西。如果是这样,那么在J2SE 1.4及更早版本中编写的代码将会出现问题。

0
假设我们有一个例子:
这段程序代码的输出结果会是什么?
public class autoboxing {
public static void main(String a args) {
Integer a = new Integer(127);
Integer b = new Integer(127);
Integer c = 127;
Integer d = 127;
Integer e = new Integer(200);
Integer f = new Integer(200);
Integer g = 200;
Integer h = 200;
System.out.println((a == b) + ' " + (c =-- d) + " " + (e==f)+ " "+ (g == h));

.

当您使用new运算符创建一个整数对象时,它每次都会返回一个新对象。如果两个引用变量引用了两个不同的对象,则使用“==”运算符比较这两个引用变量时,该运算符将返回false。
因此,
(a == b)和(e == f)表达式返回false。Integer类在-128到127之间缓存值。
当您使用“==”运算符比较两个整数对象时,如果这两个整数对象是通过自动装箱创建的,则将调用value0f(int i)方法。 答案:False True False False 以下是该方法的实现
public static Integer value0f(int i) {
if (i >= IntegerCachedow && i <= IntegerCache.high)
return IntegerCache.cacheli + (-IntegerCachedow));
return new Integer(i);

从上面的实现中,以下是结论

  1. 如果两个Integer对象的值在-128到127之间,此方法返回相同的值。因此(c == d)返回true。

  2. 如果两个Integer对象的值超出范围-128到127,此方法将返回不同的新Integer对象。因此(g == h)返回false

有关该方法的更多详细信息,请参见: https://dev59.com/h2Ei5IYBdhLWcg3w2PSB


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接