instanceof - incompatible conditional operand types
Asked Answered
T

3

59

The following compiles fine:

  Object o = new Object();
  System.out.println(o instanceof Cloneable);

But this doesn't:

  String s = new String();
  System.out.println(s instanceof Cloneable);

A compiler error is thrown.

What is the problem?

Tenacious answered 31/3, 2010 at 8:10 Comment(1)
if you are using eclipse, take a look at SomeGuys answer.Overplay
C
61

A more blatant incarnation of your problem is the following:

if ("foo" instanceof Number)
   // "Incompatible conditional operand types String and Number"

This is specified in JLS 15.20.2 Type comparison operator instanceof:

RelationalExpression:
       RelationalExpression instanceof ReferenceType

If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error, then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.

That is, since this cast expression generates a compile time error:

(Number) "foo"

so must this expression:

("foo" instanceof Number)

Your case is a bit more subtle, but the principle is the same:

  • String is a final class
  • String does not implement Cloneable
  • Therefore you can't do (Cloneable) aString
  • Therefore also you can't do aString instanceof Cloneable
Colorful answered 31/3, 2010 at 9:41 Comment(2)
Although this answer is very helpful, it lacks the special case mentioned by SomeGuy below, which was the issue for both me and apparently many others.Shotwell
Just to add to this, if you're missing an import for the type you're trying to use in the instanceof expression your IDE may raise this error instead of complaining about the missing import. This can lead to a confusing 'false-positive' kind of issue if you've got a valid class but have forgotten to import it.Iq
E
162

A related issue that I have come across recently (and which led me to this page, before I figured out what was going on) is that the Eclipse environment can report "Incompatible conditional operand types" in an 'instanceof' expression erroneously due to a missing 'import' statement for the type on the right of the 'instanceof'. I spent a while trying to figure out how the types in question could possibly be incompatible before figuring out that a missing import was causing the whole problem. Hopefully this information saves somebody some time.

Ebneter answered 4/1, 2012 at 19:10 Comment(7)
ECLIPSE USERS READ THIS ANSWER!Graner
Agreed. I figured this out myself when I tried to set a variable, something like MyType c = (MyType)myString... instead of giving me the expected error, it told me the type MyType was unknown. The fact that this answer got so many more upvotes than the accepted answer shows how pervasive this problem is!Urbai
IMPORTANT - As Some Guy mentioned, the missing import is in the file for the type on the RIGHT side of the instanceof.Tribalism
Even with the correct import (either as an import declaration or using the full class name) it still happens to me in Eclipse ADT (Android) when I try to do if (objectInstance instanceof JSONObject) or if (objectInstance instanceof JSONArray). As mentioned by @polygenelubricants if I try to perform a cast such as JSONObject jsonObject = (JSONObject)objectInstance; a compile-time error is shown: Cannot cast from Object to JSONObject. If this is a bug in Eclipse, where should I report it (though Google may not be supporting Eclipse anymore)?Blissful
Thank you very much, this is indeed the problem... I'm so confused why it recognized one fragment, but gave this error to another. Turned out one fragment extended from android.app, while another extended support.v4.app, meanwhile the activity where they meet import support.v4.app, thus one from android.app wasn't recognizedEaddy
Note that the import must be the correct one if there are multiple classes with the same name on your classpath. I was confused for a few minutes by "foo instanceof Item" when I know that it can be; eventually I realized that Eclipse had added an import statement for "Item" from a package inside a dependent jar, which I hadn't noticed at the time. Corrected the import statement and all was well.Blubber
Does not work for me ! I have the class already in my java file and its still showing the same errorLancelot
C
61

A more blatant incarnation of your problem is the following:

if ("foo" instanceof Number)
   // "Incompatible conditional operand types String and Number"

This is specified in JLS 15.20.2 Type comparison operator instanceof:

RelationalExpression:
       RelationalExpression instanceof ReferenceType

If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error, then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.

That is, since this cast expression generates a compile time error:

(Number) "foo"

so must this expression:

("foo" instanceof Number)

Your case is a bit more subtle, but the principle is the same:

  • String is a final class
  • String does not implement Cloneable
  • Therefore you can't do (Cloneable) aString
  • Therefore also you can't do aString instanceof Cloneable
Colorful answered 31/3, 2010 at 9:41 Comment(2)
Although this answer is very helpful, it lacks the special case mentioned by SomeGuy below, which was the issue for both me and apparently many others.Shotwell
Just to add to this, if you're missing an import for the type you're trying to use in the instanceof expression your IDE may raise this error instead of complaining about the missing import. This can lead to a confusing 'false-positive' kind of issue if you've got a valid class but have forgotten to import it.Iq
S
31

The compiler knows that String is a final class and doesn't implement Cloneable. So no instance of String can ever be an instance of Cloneable. It's stopping you from thinking you've got a meaningful test when actually it will always print "false".

Sowder answered 31/3, 2010 at 8:12 Comment(5)
Yes, which is why it's odd that if (s instanceof String) is fine, since it always returns true...Viosterol
Why it allows the opposite? I mean given a class that implements another class, X instanceof Y will compile even if it's always true. Why the inconsistency?Yance
@MarounMaroun: Bear in mind that if X is null, instanceof will return false... so the only time where it would be relevant would be for non-null constants (which is basically only strings) or new Foo() expressions. I think it's reasonable for that not to have a special rule in the language spec.Sowder
@JonSkeet I know, but if X implements Y, then x instanceof Y is always true, why it's not a problem for the compiler? (Where it's a problem for it if the result of instanceof is always false).Yance
@MarounMaroun: That doesn't make sense - either X is a class, in which case X instanceof Y won't compile, or X is an expression, in which case (other than for the examples listed above) it might have a value of null, in which case the result isn't always true. It's not that it's a problem for the compiler when it's always false - the compiler is just following the language spec which forbids it.Sowder

© 2022 - 2024 — McMap. All rights reserved.