0

I have a question about Parametric Polymorphism. How do I determine the actual type and avoid casting If I have a collection with a mix of child types. For example

    class Animal{

    }

    class Bird extends Animal{
          void fly(){}
    }

    class Dog extends Animal{
          void bark(){}
    }

    ArrayList<Animal> list = new ArrayList<Animal>();

The problem is how do I know which one is which when I iterating through the Animal collection. Do I need to use instanceof to check the actual type every time?

    for(Animal animal : list){
          if(animal instanceof Dog){
                ((Dog) animal).bark();
          } 
          else ((Bird) animal).fly();             
    }
2
  • 1
    Ideally you would be doing a similar action (ex. speak()) on each item which you could declare on the base class and override in the subclass. Then you do not need to worry about the type. If you proceed as you are, then yes, you need to cast to call the method. (I am consciously excluding the option of using reflection to call methods) Commented Nov 15, 2012 at 19:43
  • You can't avoid unless you move bark() and fly() to the super class Animal. Commented Nov 15, 2012 at 19:44

3 Answers 3

6

If you need to do this, that means that's a common action. You usually would have this :

abstract class Animal {
     abstract void act();
}

class Bird extends Animal{
      void fly(){}
      void act(){
         fly();
      }
}

class Dog extends Animal{
      void bark(){}
      void act(){
         bark();
      }
}

and in your loop you would simply call the act method :

for(Animal animal : list){
    animal.act();
}
Sign up to request clarification or add additional context in comments.

Comments

0

You should not have list like that. Otheriwse instanceof (or .getClass()), followed by a downcast is the only option.

1 Comment

Are you saying separate them into 2 list ?
0

Using instanceof would defeat the purpose of Generics. The point of generics is to define behavior so that you don't care what the types are. Example:

public interface Animal {
    void speak();
    void fly();
}

public class Dog implements Animal {
    public void speak() {
        System.out.println("Woof!");
    }
    // Do nothing!
    public void fly() { }
}

public class Bird implements Animal {
    public void speak() {
        System.out.println("Tweet!");
    }
    public void fly() {
        System.out.println("I'm flying!!");
    }
}

public static void main (String[] args) {
    // list populating removed
    for(Animal animal : list) {
        animal.speak();
        animal.fly();
    }
}

See? You don't actually care about what type the animal is at runtime. You let the objects do what they're supposed to.

By the way, if you did want only Bird to have a fly() method, then you wouldn't try to call the fly() method on all instances of Animal... you would have a different List<Bird>

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.