11

So I'm fairly new to programming in the real world (outside of academic projects) and have come across lots of posts saying that using instanceof is a bad thing to use to determine what class a specific object is.

My situation is that I have three classes, a base product class, one that extends off that and another that extends off that. These are all stored in the same table in a database and I have some code that needs to use the methods on each to pull data off them.

What is the best practice to get around this way of doing it? I have read some things about polymorphism but I can't find any examples that fix the issue I have. They all usually override a method which for me won't work as I need to pull different things from the different objects.

Is there a better way to do this or am I stuck with using instanceof or some sort of reflection to get the fields specific to the objects?

2
  • 10
    It's not that the keyword instanceof is wrong; trying to find the class of an object is usually the problem. Not always wrong, but probably in your case it is. Maybe if you tell us what you're trying to accomplish, we can suggest a solution using polymorphism.
    – Andres F.
    Jan 18, 2013 at 16:04
  • 2
    Okay, each class has data specific to it. I want to pull the specific data from these. I think I have realised the answer with the help I've had. Something like a method called getSpecifics() that is implemented differently on each, with each returning the data specific to the class? Jan 18, 2013 at 16:09

4 Answers 4

17

The reason instanceof is discouraged is that it's not OOP.

There should be no reason for the caller/user of an object to know which concrete class it is an instance of beyond which type the variable it is declared as.

If you need different behavior in subclasses add a method and implement them differently.

4
  • 1
    So a method getSpecifics()(or something similar) on each class that will return the specifics for each class. Is this the best approach? Jan 18, 2013 at 16:07
  • @Schmooo You really need to think about where the common functionality exists within the class tree and what contracts exist at each level.
    – user40980
    Jan 18, 2013 at 17:55
  • 3
    But what about a case when your object cross layers and the type information is lost? Example I create a List. I pass it to an object that take any Iterable. Now that second object pass it to a third object that take either a List for optimization, or an Iterable but is much slower. The second shouldn't know that its a list, but the third one would very like to know. Shouldn't the third object check for instanceof to see if it can apply the optimization? See for example guava FluentIterable that does just that. Jan 18, 2013 at 19:42
  • 1
    I'd say that's not always the case that you have to add the method to the class. For example, some code gets an exception and is supposed to do something with it depending on its type. Say, makes a report or does something to recover from error. This kind of functionality definitely doesn't suit the exceptions. Or, if the classes come from some external library, then you don't even have the means to modify these classes. In this case I think it is absolutely valid to rely on the instanceof.
    – Malcolm
    Feb 4, 2013 at 7:30
9

instanceof isn't necessarily a bad thing, however it is something that one should look at.

An example of where it works correctly is in a place where one gets a collection of the base type and you only want the ones of a subtype. Getting the network addresses from NetworkInterface.getNetworkInterfaces() returns back NetworkInterface objects which have a collection of InetAddress objects, some of which are Inet4Address and some are Inet6Address. If one wants to filter the collection for Inet4Address objects, it is necessary to use instanceof.

In the situation that is being described in the original post, there is a Base class, something that extends that base class and something that extends the extended class. While not completely informative, this seems to have the underpinnings of some less than ideal design.

When you are returning a base class unless there is good reason for it being designed that way (backwards compatibility between specifications of an earlier version) you shouldn't be trying to peek at the underlying types. If you are returned a Set, you know you are getting a set. It allows the developer to later change his or her mind to return a more specific type (SortedSet) or change the underlying type (HashSet to TreeSet) without breaking anything.

Reconsider your design of how the objects are structured and parented to see if one can make an better class model that is doesn't require a distinction of types.

2
  • It's possible that having the interface specify a isOfType(SomeEnum.IPv4) method could be a better way to filter for such qualities than inspecting the concrete type via instanceof. What if you want to split your IPv4 implementation class later? Not that this is always better, but it's a consideration. Jan 22, 2013 at 1:40
  • @StevenSchlansker That could work for that specific class. But what if one needed to inspect the concrete type to see if a cast is possible (or would one just cast and catch the exception?) Inet6Address implements more methods than InetAddress. It would be difficult for it to work with interfaces (an enum that enumerates every class in the package? or class loader?) and that would mean the method would need to be implemented by hand (or some reflection code in Object). Consider how to do (o instanceof Serializable) || (o instanceof Externalizable). instanceof is better than the alternative
    – user40980
    Jan 22, 2013 at 22:54
1

You can use getClass() method.

Are you sure you need three different classes? Maybe one class with a switch inside will serve better?

13
  • 7
    getClass and instanceof share downsides. Polymorphism is better than both when it fits, and I don't see it not fitting OP's use case.
    – user7043
    Jan 18, 2013 at 16:01
  • I have nothing against your first sentence. But the second one - sorry, I can't understand what do you mean at all.
    – Gangnus
    Jan 18, 2013 at 16:04
  • 1
    With getClass do I not still share the same issue as using instanceof? I'll still have to find out which I have and then call a set of functions. Ideally I want a method that returns the data specific to that class without needing to cast to that object. Jan 18, 2013 at 16:05
  • I'm complaining about you ignoring Polymorphism, as it's often a better choice. I'm pretty sure the use case in the question can be done with polymorphism, so I don't see the need to use either. (Apart from that, just reproducing someone else's answer isn't nice.)
    – user7043
    Jan 18, 2013 at 16:07
  • 2
    @Gangus I don't think of this as an "attack", I mean no offense. But whatever. No, the question isn't "what else can be used", it's "is there a better way to do this". Unless you want to argue getClass is a better way to do it, it has no business taking up most of an answer ;-)
    – user7043
    Jan 18, 2013 at 16:21
1

Typically when I find myself wanting to know the type of something it means I implemented my object structure wrong. Most of these times it comes down to violating LSP.

There are times however where I wish I'd have a way to do dynamic dispatch and save a ton of boiler plate code and futureproof my object structure. C# provides the dynamic keyword in the newer installments of the framework but as far as I know Java still does not have something similar.

That said, instanceof is generally better than comparing classes as it will support inheritence properly. You can also use methods like isAssignableFrom and others from the reflexion API. If you want to implement something like dynamic dispatch it can be done via the reflection API but beware, it will be slow. Use with caution, ideally you should fix the object structure and desing of your app if you can.

Hope this helps

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.