views:

858

answers:

7

Is there anything tricky I should know about instanceof? I'm passing a list of objects through a few methods and testing whether these objects implement a particular interface using instanceof. In some cases, instanceof correctly identifies objects as implementing the interface, in other cases it doesn't. It appears to be giving me inconsistent results on the same object in different places. Is there any trick/gotcha I should be aware of here?

In anticipation of comments you might have:

1) I know instanceof is bad form. I'm working with a less-than-perfect object hierarchy that can't be changed, and this is the least bad thing I can think to do.

2) I'm working to create a code example, but I'll need to simplify my code a lot if I'm going to paste in anything useful here. In the meantime, if you've seen this before and can shed some light, please do.

+2  A: 

The only gotcha I know of is that null is instanceof no type.

cadrian
+9  A: 

Are you loading any types dynamically, potentially from different classloaders? The only time I've seen apparently inconsistent results was when I had two lines of code which look like they refer to the same type, but which have actually loaded that type from different classloaders.

Jon Skeet
Gosh, I don't _think_ so. The strangeness is popping up when running a simple junit test case. This gives me enough information to assume that I've done something dumb and just need to simplify. Thanks.
morgancodes
A: 

You may be wanting "isAssignable" instead of instanceof:

if (MyInterface.isAssignableFrom(myObject.getClass())) {
  //  do work here
}

This will return true for classes that implement your interface.

Todd R
So does instanceof.
Michael Myers
Exactly the same as instanceof, but throws an NPE if myObject is null.
cadrian
...better to use MyInterface.class.isInstance(myObject) - this doesn't throw an NPE. Even this is pointless if you know MyInterface at compile time - might as well use instanceof
oxbow_lakes
+5  A: 

instanceof always returns false for null. It does not compile if it would be impossible for the static type on the left cannot be an instance of the specified type. Other than that, it should work without surprise.

Unlike C++ (and I believe Smalltalk), an object cannot change type at runtime. In C++ the type changes during construction, so that methods cannot be called from a constructor to derived class [subclass] methods.

Tom Hawtin - tackline
+3  A: 

As long as you have no classloading problem, instanceof works consistently. I guess you know A instanceof B returns true if the A is inherited from B, or some of the interfaces A implements or classes A extends, are instanceof B.

If you get false when you expect true, you probably are trying to compare instances comming from different ClassLoaders.

siddhadev
+5  A: 

Ok, problem solved. As usual, the problem was less wierd than I thought. The project I'm working on is in the unfortunate condition of having some duplicate class names. I was creating the class using foo.MyInterface and testing for instance of bar.MyInterface. Thanks for the responses. It really did help me think it through.

morgancodes
Ironically, I nearly included this possibility in my answer, but for some reason didn't in the end. That'll teach me - next time I'll post all ideas, no matter how silly :)
Jon Skeet
A: 

Answer from Todd R is not so silly : with proxying (e.g. Spring annotations dynamically charging beans), you must use

Class.isInstance(obj)

if it is not an immediate interface (a implements interface1; interface1 extends interface2).

a instanceof interface2 

won't work then, but well

interface2.class.isInstance(a)

;o)

Elnourso