61

The following code,

private boolean compare(Object a, int b) {
    return a == b;
}

compiles in Java 7, but it results in the following error in Java 8:

incomparable types: int and Object

Looking at the following question:

Comparing Object and int in Java 7

It seems like Java 6 and Java 8 don't let you compare int and Object, while 7 does. Is there any documentation on this?

I'm interested in the background knowledge that informed these decisions. It seems like they were undecided or something.

I'm using IntelliJ IDEA 14.1.4 with JDK 1.7.0.51.

Community
  • 1
  • 1
Matt_Bro
  • 14,062
  • 2
  • 28
  • 41
  • 2
    Is the error shown in eclipse (ie. when using ecj) or by the JDK compiler? I'd guess this is an error in ecj... – Axel Sep 17 '15 at 14:09
  • 2
    If that's the case, I would think Java 7 made a mistake – dragon66 Sep 17 '15 at 14:19
  • With Oracle's Java 7, I get "Incompatible operand types: Object and int". Are you providing the exact code that you observed in compiled in Java 7? – Andy Thomas Sep 17 '15 at 14:22
  • @AndyThomas i´d guess it depends on the specific version of the 1.7 jdk. llogiq couldn´t compile with jdk 1.7.0_75 while wero could compile it with jdk 1.7.0_71. Maybe they did a bug fix in between these versions? – SomeJavaGuy Sep 17 '15 at 14:33
  • Compilation fails on jdk 1.7.0_67 – algiogia Sep 17 '15 at 14:50

4 Answers4

30

Java 7 applies autoboxing to the int.

 private boolean compare(java.lang.Object, int);
   Code:
      0: aload_1
      1: iload_2
      2: invokestatic  #2       // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      5: if_acmpne     12
      8: iconst_1
      9: goto          13
     12: iconst_0
     13: ireturn

I created this with build 1.7.0_71-b14

EDIT:

This behaviour was recognized and treated as bug by Oracle:
JDK-8013357: Javac accepts erroneous binary comparison operations

Relevant JLS section is 15.21. Javac seems to treat this as a reference comparison, but a reference comparison is only allowed when BOTH operands are reference types.
...
The type rules for binary comparisons in JLS Section 15.21 will now be correctly enforced by javac. Since JDK5, javac has accepted some programs with Object-primitive comparisons that are incorrectly typed according to JLS 15.21. These comparisons will now be correctly identified as type errors.

wero
  • 32,544
  • 3
  • 59
  • 84
22

The JLS - Chapter 15. Equality Operators mentions 3 different == operators: numerical, boolean and reference. None of the == operators can happen in your example, so we conclude that the statement is illegal.

Let's see why == cannot be applied in your example:

Now let's assume it's legal and the compiler changed the line to:

if (a == new Integer(b))

What do you expect the result to be? The condition will never evaluate to true, so it makes sense that it's a bug that was fixed in Java 8.

Maroun
  • 94,125
  • 30
  • 188
  • 241
  • 19
    However autoboxing is done using `Integer.valueOf`. Since `Integer.valueOf` sometimes returns values from a pool, the result could be `true`. – fabian Sep 17 '15 at 14:28
  • 3
    @fabian So, never true *in a reasonably useful or intuitive way*. – Yakk - Adam Nevraumont Sep 17 '15 at 17:30
  • 2
    @MarounMaroun Well, for the code in the answer, it will definitely never be true. `new Integer(b)` always creates an object, whereas `Integer.valueOf(b)` might not. – user253751 Sep 18 '15 at 02:27
  • As other commenters have said, this answer is wrong. Comparing an integer and Object is well defined with autoboxing. – Navin Sep 18 '15 at 04:11
7

I could not get an example to compile (fixing bool → boolean) with javac 1.7.0_75, nor with javac 1.8.0_60. I don't have a JDK6, but I don't think it should have worked there either. Perhaps it is an earlier ecj incompatibility, as Axel hints, or a bug in a different minor version of javac.

In any event, if it works, it is due to autoboxing. This may have been pared back in preparation for Java 8, because streams and autoboxing don't mix too well.

llogiq
  • 13,815
  • 8
  • 40
  • 72
5

It shouldn't have compiled, according to JLS 7. int can be compared to boxed numeric types, i.e. Byte, Short, Character, Integer, Long, Float, Double. But that is all.

And if comparison is between int and say Float, Float will be unboxed first, so that the comparison is between float and int. It'll make no sense to do the other way around - box int then examine the identity of the Integer (with a Float no less).

ZhongYu
  • 19,446
  • 5
  • 33
  • 61