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?

SyntaxT3rr0r
  • 27,745
  • 21
  • 87
  • 120
java_geek
  • 17,585
  • 30
  • 91
  • 113

3 Answers3

161

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.

Some Guy
  • 1,611
  • 2
  • 10
  • 2
  • 21
    ECLIPSE USERS READ THIS ANSWER! – Shane Aug 22 '12 at 21:11
  • 1
    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! – fool4jesus Aug 16 '13 at 13:30
  • 1
    IMPORTANT - As Some Guy mentioned, the missing import is in the file for the type on the *RIGHT* side of the `instanceof`. – Cory Klein Mar 18 '14 at 18:02
  • 2
    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)? – Piovezan Mar 13 '15 at 14:02
  • 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 recognized – Konayuki Feb 18 '16 at 01:08
  • 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. – Mark Phillips Dec 23 '19 at 20:10
  • 1
    Does not work for me ! I have the class already in my java file and its still showing the same error – SpawN Feb 11 '21 at 07:52
60

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
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • 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. – Simon Forsberg Oct 22 '12 at 23:40
  • 13
    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. – aroth Jan 29 '13 at 13:45
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".

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Yes, which is why it's odd that `if (s instanceof String)` is fine, since it always returns true... – Perkins May 31 '15 at 18:50
  • 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? – Maroun Jan 03 '16 at 15:35
  • 1
    @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. – Jon Skeet Jan 03 '16 at 15:36
  • @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). – Maroun Jan 03 '16 at 15:39
  • @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. – Jon Skeet Jan 03 '16 at 15:41