9

The following code

public class TestComparison {
    public static void main(String[] args) throws Exception {
        boolean b = true;
        Object o = new Boolean(true);
        System.out.println("comparison result: "+ 
            (o == b)); // Eclipse complains about this expression
    }
}

compiles without errors with javac V1.7.0_15, and prints "false" when run. However, Eclipse Juno complains about "Incompatible operand types Object and boolean".

Apparently javac autoboxes the primitive boolean b, and then compares o and autoboxed b by object equality, yielding false, while Eclipse refuses to do the autoboxing.

Which is the right behaviour according to the Java Language Specification? Where should I file a bug?

Note: If I change the type of o to Boolean, things work as expected: Eclipse accepts the code, and the code prints "true".

Runnable version on ideone.com

sleske
  • 81,358
  • 34
  • 189
  • 227
  • 1
    Check your Eclipse Settings and see if there's something funky: Project Properties -> Java Compiler ->Errors/Warnings -> Potential Programming Problems –  May 27 '13 at 09:47
  • 1
    Depends what you "expected" - should it box `b` and use reference equality (printing false) or unbox `o` and use primitive boolean equality (printing true)? – Ian Roberts May 27 '13 at 09:48
  • [java AutoBoxing rules](http://jcp.org/aboutJava/communityprocess/jsr/tiger/autoboxing.html) – Subhrajyoti Majumder May 27 '13 at 09:50
  • @IanRoberts: It can't do the latter; the static type of `o` is `Object`. – Oliver Charlesworth May 27 '13 at 09:56
  • 1
    In java 6 the code does not compile. It seems there was some changes in specification between java 6 and 7 that allow such behavior, see the answers to this question: http://stackoverflow.com/questions/16119638/differences-in-auto-unboxing-between-java-6-vs-java-7. The relavant part is: An expression of a reference type may undergo casting conversion to a primitive type without error, by unboxing conversion. – dcernahoschi May 27 '13 at 10:01

2 Answers2

7

It's your project language level setting. You are probably using a Java 7 compiler with Java 6 semantics. I don't have Eclipse here, but I reproduced it in IntelliJ, which gave errors when the language level was on Java 6, even though the compiler I used was 7. I guess Eclipse has the same. This link explains it.

Erik Pragt
  • 13,513
  • 11
  • 58
  • 64
  • 1
    This seems to be the problem. I can reproduce the problem with `javac -source 1.6`, so it seems the problem is caused by the change from 1.6 to 1.7. However, Eclipse shows the error even for "Compiler compliance level = 1.7". This might be a bug in the Eclipse compiler. – sleske May 27 '13 at 10:13
  • @sleske I confirm all that :/ – A4L May 27 '13 at 10:15
3

Concerning your 'Note' that the code compiles and works when o is changed to Boolean:

This code:

public class Tester{
  public static void main(String args[]){
    Boolean one = new Boolean(true);
    Object two = new Boolean(true);
    boolean three = true;
    System.out.println("SAME 1:2 " + (one == two) + " 1:3 " + (one == three) + " 2:3 " + (two == three));
    System.out.println("EQUAL 1:2 " + (one.equals(two)) + " 1:3 " + (one.equals(three)) + " 2:3 " + (two.equals(three)));
  }
}

produces this result:

SAME 1:2 false 1:3 true 2:3 false
EQUAL 1:2 true 1:3 true 2:3 true

To see why this is, we need to consider the compile-time types of the various expressions:

  • one == two compares a Boolean with an Object - these are both reference types, so the test is reference equality (Java Language Specification, Java SE 7 edition, §15.21.3)
  • one == three compares a Boolean with a boolean - this is treated as a comparison of primitive boolean values (§15.21.2); one is unboxed and compared with three.
  • two == three compares an Object with a boolean - in this case the boolean is converted to Object by a casting conversion (§5.5, in this case boxing boolean to Boolean and then widening Boolean to Object) and the two are then compared for reference equality.

The EQUAL line is much simpler - all three cases are calls to Boolean.equals(Object other), using boxing when the argument is three.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
Angelo Fuchs
  • 9,825
  • 1
  • 35
  • 72
  • Thanks for the clarification. So for `two==three`, both a cast and boxing/unboxing are necessary, and Java will first autobox, and then cast. – sleske May 27 '13 at 12:43