Java에서 == 와 != 를 사용한 Integer 비교 – 버그?

Tags:

헉.. 응답 받는데 최소 3주나 걸린다는군요;;

dateCreated: Sun Feb 19 09:19:40 MST 2006
type: bug
status: Waiting
category: java
subcategory: specification
release: 5.0
hardware: x86
OSversion: win_xp
priority: 4
synopsis: Integer comparisons with == and != operator
description: FULL PRODUCT VERSION :
java version “1.5.0_06”
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Windows XP

A DESCRIPTION OF THE PROBLEM :
As of JDK5, operator <, <=, >=, >, ==, != can be used when comparing two integers. For example, given i and j declared as below:

Integer i = new Integer(5);
Integer j = new Integer(5);

i < j and j > i return false, but operator == is not redefined for backward compatability, i.e., i == j return false because i and j are differerent instances.

However, operator == compare the value of two integer if one of them is primitive. For example, i == 5 return true. This is allowed because it won’t do any harm to backward compatability issue. This is all I know about == operator.

Things get complicated, however, when it comes to autoboxing. And I’ve found the following weird behavior in the current relase of JDK 5.

import java.util.Random;

public class Test {
   public static void main(String[] args) {

       Integer i;
       Integer j;

       i = new Integer(5);
       j = new Integer(5);

       // Must be diffrent objects, because of new.
       System.out.println("Integer/Integer");
       System.out.println( i == j );

       i = 5;
       j = 5;

       // Must be the same, because these two numbers are seen
       // during compilation stage.
       System.out.println("Autoboxing/Autoboxing");
       System.out.println( i == j );


       // Must be the same, because 5 in the expression is seen
       // during compilation stage.
       System.out.println("Autoboxing/primitive");
       System.out.println( i == 5 );

       i = 5;
       j = new Integer(5);

       // Must be different, because of new.
       System.out.println("Autoboxing/Integer");
       System.out.println( i == j );

       i = 5;
       j = foo();

       // Must be different, because of implicit new during autoboxing.
       System.out.println("Autoboxing/Integer(function call; no compiler optimization)");
       System.out.println( i == j );

       i = 5;
       j = bar();

       // Must be different, because of explicit new.
       System.out.println("Autoboxing/Integer(function call; with compiler optimization)");
       System.out.println( i == j );
   }

   public static Integer foo() {
       // Purposely preventing compiler optimization
       Random r = new Random();
       Integer result = r.nextInt(3);
       result += (5 - result);

       return result;
   }

   public static Integer bar() {
       // Let this number be hardwired
       return new Integer(5);
   }
}

This program returns

Integer/Integer
false
Autoboxing/Autoboxing
true
Autoboxing/primitive
true
Autoboxing/Integer
false
Autoboxing/Integer(function call; no compiler optimization)
true
Autoboxing/Integer(function call; with compiler optimization)
false

As the comment, almost all result seem to be reasonable, except for the last two. On one hand, i == foo() return true. On the other hand, i == bar() return false. That’s strange because it is manifest that foo and bar return Integer(5).

This might be a bug. At the very least, I need justification.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED –
Autoboxing/Integer(function call; no compiler optimization)
false
Autoboxing/Integer(function call; with compiler optimization)
false
ACTUAL –
Autoboxing/Integer(function call; no compiler optimization)
true
Autoboxing/Integer(function call; with compiler optimization)
false

REPRODUCIBILITY :
This bug can be reproduced always.

———- BEGIN SOURCE ———-

import java.util.Random;

public class Test {
   public static void main(String[] args) {

       Integer i;
       Integer j;

       i = new Integer(5);
       j = new Integer(5);

       // Must be diffrent objects, because of new.
       System.out.println("Integer/Integer");
       System.out.println( i == j );

       i = 5;
       j = 5;

       // Must be the same, because these two numbers are seen
       // during compilation stage.
       System.out.println("Autoboxing/Autoboxing");
       System.out.println( i == j );


       // Must be the same, because 5 in the expression is seen
       // during compilation stage.
       System.out.println("Autoboxing/primitive");
       System.out.println( i == 5 );

       i = 5;
       j = new Integer(5);

       // Must be different, because of new.
       System.out.println("Autoboxing/Integer");
       System.out.println( i == j );

       i = 5;
       j = foo();

       // Must be different, because of implicit new during autoboxing.
       System.out.println("Autoboxing/Integer(function call; no compiler optimization)");
       System.out.println( i == j );

       i = 5;
       j = bar();

       // Must be different, because of explicit new.
       System.out.println("Autoboxing/Integer(function call; with compiler optimization)");
       System.out.println( i == j );
   }

   public static Integer foo() {
       // Purposely preventing compiler optimization
       Random r = new Random();
       Integer result = r.nextInt(3);
       result += (5 - result);

       return result;
   }

   public static Integer bar() {
       // Let this number be hardwired
       return new Integer(5);
   }
}

———- END SOURCE ———-
workaround: N/A

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *