2

I have many sub-classes implementing the superclass Animal (Dog, Cat, Mouse, etc)

So I do:

Animal[] arrayOfAnimals = new Animal[100];

I put in it Dog,Cat etc objects.

When I get something from it I do

If(arrayOfAnimals[1] instanceof Dog) {
    ((Dog)(arrayOfAnimals[1])).speak();
}

else if(arrayOfAnimals[1] instanceof Cat) {
    ((Cat)(arrayOfAnimals[1])).speak();
}

Because I need to know if that Animal is a Cat or a Dog because,for example, each one speaks differently.

Now assuming I have many subclasses of Animals, I will consecutively get many "else if..."

My question is: Is there a way to avoid this? I have already tried using an interface (Animal -> interface, Dog,Cat etc implementing animal), but in my project an array has to be cloneable, and you can't clone an array "Animal [] arrayOfAnimals" if Animal is an interface (objects inside that array will not be cloned)

j0k
  • 22,600
  • 28
  • 79
  • 90

2 Answers2

9

Because i need to know if that Animal is a Cat or a Dog because,for example, each one speaks differently.

That sounds like it's an implementation detail - if every animal can speak in some form, you should put the speak() method into Animal as an abstract method. Each subclass will then override it to provide the implementation. Then you can just use

arrayOfAnimals[1].speak();

... and polymorphism will take care of using the right implementation.

You can clone an array of an interface type, btw:

interface Foo {
}

class FooImpl implements Foo {
}

public class Test {
    public static void main(String[] args) {
        Foo[] foos = { new FooImpl() };

        Foo[] clone = (Foo[]) foos.clone();
        System.out.println(foos[0] == clone[0]); // true
    }
}

Note that regardless of the type involved, calling clone() on array won't clone each element - the new array will contain the same references as the old array. It's a shallow copy. If you want to do that, you'll have to code it yourself (or find a third party library).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • the array will be cloned, but not the object inside it. Tried with System.out.println(arrayOfAnimals[1]); and System.out.println(ArrayCloned[1]); : they got same hash id – Francesco Tronca May 23 '12 at 18:29
  • @FrancescoTronca: Yes, that's what I say in the final paragraph. That will happen whether the array type is an interface or not. – Jon Skeet May 23 '12 at 18:30
  • I tried it, thats why you cant clone an array of interfaces (assuming you want to clone also the object inside that): you cant clone an Animal object if Animal is an interface, cos Animal can't implement Cloneable (an interface can't implement another one =P ) – Francesco Tronca May 23 '12 at 18:31
  • @FrancescoTronca: An interface can *extend* another one: `public interface Animal extends Cloneable`. No problem. – Jon Skeet May 23 '12 at 18:34
  • Don't know why didn't work then :( Btw i resolved with the abstract method, you r a God, thanks! – Francesco Tronca May 23 '12 at 18:44
1

Why don't you move speak() to the superclass and let the subclasses override it?

Selim
  • 1,013
  • 9
  • 15
  • because when you will use arrayOfAnimals[1].speak() he will use the method of the superclass Animal. Now I will try with it defined as abstract, like Jon Skeet said – Francesco Tronca May 23 '12 at 18:28
  • 3
    Ummm, no it wont. The JVM uses virtual method invocation to dynamically select the actual version of the method that will run. So you can't call any method that is not declared in Animal but whatever you call will be invoked on the actual referred instance type. If you make it abstract like John Skeet said -which is not wrong btw- you are only forcing it to be overridden. The end result is the same, same principle. On the other hand, you can specify a default implementation via providing an implementation for it. – Selim May 23 '12 at 18:49