views:

582

answers:

6

I have two classes A and B, where B is subclass of A and A is not abstract. Therefore I can have objects that are instance of A and objects that are instance of B (and therefore of A).

How can I distinguish objects that are only instance of A?

Sure, I can write something like "object instaceof A && !(object instance of B)" but this is a very poor design since I'll need to change the code every time I add new subclasses to A. Better alternatives?

+7  A: 
object.getClass() == A.class
Yishai
+2  A: 

Doesn't this show that B isn't really an A? I'm not entirely sure you should get into this situation? Perhaps you could improve your design??

Egwor
+5  A: 

Why you want them to distinguish? Usually this is the opposite of OO. You have different instances that you don't need to distinguish because the different implementation does everything right.

If you need to do so than there should be a protocol for it. Have a method for that purpose that returns something to recognize. That is more flexible,too.

I would instanceOf and getClass already consider bad style if this is used without good reason

Norbert Hartl
+1 with your answer. Java is a static language, if you have to consider the dynamic type of your objects have a look at the visitor pattern.
pgras
this looks like case of Dispatcher pattern to be solved in very OO way. The pattern enables different behaviours dependent on the oject type, but I am not sure if it is possible in Java. IMHO languages need better support for meta programming...
Gabriel Ščerbák
+2  A: 

A better approach is to make the test the result of a method

class A {
   public boolean isSomeTest() {
      return true;
   }
}
class B extends A {
   public boolean isSomeTest() {
      return false;
   }
}

Then if you add a C which extends A you can allow it to return true or false.

The name of isSomeTest should make it clear what returning true or false should mean.

Peter Lawrey
+1  A: 

This is what I think you're saying:

public class A {
}

public class B extends A {
}

later in code:

A apple = new A();
B banana = new B();

Here are some options that you may find useful:

if (apple.getClass() == A.class) { // Found an A }
if (banana.getClass() == A.class) { // This is not an A, won't get here. }
if (apple instanceof A) { // This is definitely an A }
if ((apple instanceof A) && (!(apple instanceof B))) { // It's an A but not a B }

Regarding the last option, you write the following:

Sure, I can write something like "object instaceof A && !(object instance of B)" but this is a very poor design since I'll need to change the code every time I add new subclasses to A. Better alternatives?

Polymorphism almost always helps us here. Your point about changing code every time you add a subclass is exactly the kind of symptom that you should recognize as standard object-oriented design evolution. Think about the behavior that you are trying to produce. Can you push that into the class itself rather than delegating it to an outside provider looking in that has to deduce what class it's currently working on?

Without more information, I can't give too much guidance but here's a fairly straightforward example:

// Instead of this
if (apple.isClassA()) { // run class A code
} else if (apple.isClassB()) { // run class B code
// And so forth
}

Modify the design to become more like this:

public class A {
    public void executeCommand() { 
        // run class A code 
        // This method knows that it's definitely an A, not a B
    }
}

public class B extends A {
    public void executeCommand() { 
        // run class B code 
        // This method knows that it's a B (and, therefore, an A as well).
    }
}

Where later in the execution code, you replace your previous if test with:

apple.executeCommand();
banana.executeCommand();

Admittedly, this is a nearly trivial object-oriented design review but it may shake something loose and help you with your subclassing problem.

Bob Cross
why would a banana subclass an apple?
Catchwa
Yeah, it's a funny thought, admittedly. Maybe I'm trying to genetically engineer different varieties of kids juice boxes right on the tree.I was trying to avoid the "standard" hideous conglomeration of "class A" and "A theA;" or "A aA;" Instead, A is for apple, B is for banana. If you can think of a variety of apple that starts with B, I'll change it.
Bob Cross
+1  A: 

Use the getClass method of an object against the class property:

if(someObject.getClass() == A.class){
   //some code
}
ZiG