58

How can I call the eat and drink method of the Animal class with the myAnimal instance in the code?

public class Animal {
    public void eat() {
        System.out.println("Animal Eats");
    }

    public void drink() {
        System.out.println("Animal Drinks");
    }
}

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("Cat Eats");
    }

    @Override
    public void drink() {
        System.out.println("Cat Drinks");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.eat();
        myCat.drink();

        Animal myAnimal = myCat;        
        myAnimal.eat();
        myAnimal.drink();
    }
}

Output that I am getting:

Cat Eats
Cat Drinks
Cat Eats
Cat Drinks

This is my expected output:

Cat Eats
Cat Drinks
Animal Eats
Animal Drinks
peterh
  • 11,875
  • 18
  • 85
  • 108
Hisham Muneer
  • 8,558
  • 10
  • 54
  • 79
  • 1
    You want to call the `animal` implementation **without** the `cat` implementation? – mthmulders Mar 27 '13 at 19:47
  • 9
    Unless you have a method in `Cat` witch calls `super.eat();` you cannot do it directly from `Cat` – A4L Mar 27 '13 at 19:51
  • 2
    You shouldn't expect what you're expecting ... shouldn't both in terms of the language definition and in terms of what is reasonable or desirable to want. The whole point of inheritance polymorphism is to get what you're seeing and not what you say you expect. – Jim Balter Apr 07 '17 at 04:17
  • Whilst your edits @Michael have _eliminated_ (!) what might be considered offensive in some quarters, there was a crude humour that I (as a cat lover) recognised and with the addition of a third method `sleep()` the original question would model felines I've experienced quite well. On the other hand many people wouldn't give a lump of what has been transmuted here... 8-P – SlySven Apr 08 '17 at 01:44

12 Answers12

82

You cannot do what you want. The way polymorphism works is by doing what you are seeing.

Basically a cat always knows it is a cat and will always behave like a cat regardless of if you treat is as a Cat, Felis, Felinae, Felidae, Feliformia, Carnivora, Theria, Mammalia, Vertebrata, Chordata, Eumetazoa, Animalia, Animal, Object, or anything else :-)

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 1
    Reflection won't do it either... :-) – TofuBeer Mar 27 '13 at 20:01
  • Reflection (java.lang.reflect) allows you to, among other things, call methods by their name (passed in as a string). However it still won't help since it follows the same rules as what is going on in the code you posted to begin with. – TofuBeer Mar 27 '13 at 20:06
  • @Ced correct, that doesn't compile. The rationale would be that you extended the class for a reason, and that means you have all of the behaviors of the parent. – TofuBeer Jun 08 '16 at 03:22
  • I face this interesting scenario today. What I eventually did to work around was to create a private method `connectImpl( )` and then I called that method. Otherwise, calling the original `connect( )` method routes back to the derive class and results to infinite recursion. – daparic Feb 21 '20 at 09:09
34

Here you will have an option to choose which method do you want to invoke:

public class Cat extends Animal {

    public void superEat() {
        super.eat();
    }

    public void superDrink() {
        super.drink();
    }

    @Override
    public void eat() {
        System.out.println("Cat Eats");
    }

    @Override
    public void drink() {
        System.out.println("Cat Drinks");
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
Andrii Dzhyrma
  • 351
  • 4
  • 5
9

This line:

Animal myAnimal = myCat;

assigns the variable myAnimal to the object myCat, which you've created before. So when you call myAnimal.eat() after that, you're actually calling the method of the original myCat object, which outputs Cat Eats.

If you want to output Animal Eats, you'll have to assign an Animal instance to a variable. So if you would do this instead:

Animal myAnimal = new Animal()

the variable myAnimal will be an instance of Animal, and thus will overwrite the previous assignment to Cat.

If you will call myAnimal.eat() after this, you're actually calling the eat() method of the Animal instance you've created, which will output Animal Eats.

Concluding: your code should read:

public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("Cat Eats");
    }

    @Override
    public void drink() {
        System.out.println("Cat Drinks");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.eat();
        myCat.drink();

        Animal myAnimal = new Animal();        
        myAnimal.eat();
        myAnimal.drink();
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
Piet van Dongen
  • 1,629
  • 10
  • 13
4
  • Access to static fields, instance fields and static methods depends on the class of reference variable and not the actual object to which the variable points to.
  • Remember that member variables are shadowed, not overridden.
  • This is opposite of what happens in the case of instance methods.
    In case of instance methods the method of the actual class of the object is called.

    class ABCD {
        int x = 10;
        static int y = 20;
    
        public String getName() {
            return "ABCD";
        }
    }
    
    class MNOP extends ABCD {
        int x = 30;
        static int y = 40;
    
        public String getName() {
            return "MNOP";
        }
    }
    
    public static void main(String[] args) {
    
      System.out.println(new MNOP().x + ", " + new MNOP().y);
    
      ABCD a = new MNOP();
      System.out.println(a.x); // 10
      System.out.println(a.y); // 20
      System.out.println(a.getName()); // MNOP
    }
    

In this example although the the object myCat is assigned to an Animal object reference, (Animal myAnimal = myCat) the Actual object is of type Cat and it behaves as it's a cat.

Hope this helps.

tharindu_DG
  • 8,900
  • 6
  • 52
  • 64
3

You can create constructor for class Animal, that takes another Animas as parameter, and creates new instance based on provided one.

public class Animal {
    //some common animal's properties
    private int weight;
    private int age;

    public Animal() {
        // empty.
    }

    public Animal(final Animal otherAnimal) {
        this.weight = otherAnimal.getWeight();
        this.age = otherAnimal.getAge();
    }

    public void eat() {
        System.out.println("Animal Eats");
    }

    public void drink() {
        System.out.println("Animal Drinks");
    }

    // setters and getters.
}

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("Cat Eats");
    }

    @Override
    public void drink() {
        System.out.println("Cat Drinks");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.eat();
        myCat.drink();

        // note: myAnimal is not a Cat, it's just an Animal.
        Animal myAnimal = new Animal(myCat);         
        myAnimal.eat();
        myAnimal.drink();
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
friednail
  • 334
  • 3
  • 8
  • 2
    This is known as "slicing" in C++; you "slice" the parent part of a Cat to produce an Animal that is no longer a Cat. It happens in C++ using syntax similar ot the OP's syntax. In Java, you have to do it explicitly. Note that this is an improvement, accidental slicing really sucks. – Yakk - Adam Nevraumont Apr 10 '17 at 13:10
2

If you make methods in each class static, it should work.

public class Animal {
    public static void eat() {
        System.out.println("Animal Eats");
    }

    public static void drink() {
        System.out.println("Animal Drinks");
    }
}


public class Cat extends Animal {
    @Override
    public static void eat() {
        System.out.println("Cat Eats");
    }

    @Override
    public static void drink() {
        System.out.println("Cat Drinks");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.eat();
        myCat.drink();

        Animal myAnimal = myCat;        
        myAnimal.eat();
        myAnimal.drink();
    }
}

The above code will give the following output

Cat Eats
Cat Drinks
Animal Eats
Animal Drinks
cNgamba
  • 111
  • 1
  • 10
Vbee
  • 21
  • 2
  • 5
    I don't think that's what the OP is asking for, he wants to be able to access the overridden method in an instantiated Object, I would go for something else like redesigning the objects if that is what he is requiring. – Goodwine May 15 '14 at 00:02
  • 1
    @Vbee, static methods are not overridden but hiding and it will result a compile time error in the case of using `@Override` annotation above the static method. Prefer to call static methods with _className.staticMethodName_ instead of object reference. – jundev May 26 '20 at 17:06
2

Few suggestions :

  1. Don't pass child class reference to super class and except super class method has to be invoked for overridden method. Call super class methods from super class instance.

    Animal myAnimal = new Animal();
    myAnimal.eat();
    
  2. If you want to call super class method from child class, explicitly call super class method name with super.methodName();

    public void eat() {
        super.eat();
        System.out.println("Cat Eats");
    }
    
  3. Don't override super class method in child class. Always super class method is invoked.
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
1

You can achieve what you want using the super keyword, which allows to access the overridden method.

public class Animal {
    public void eat() {
       System.out.println("Animal Eats");
    }

    public void drink() {
       System.out.println("Animal Drinks");
    }
}

 public class Cat extends Animal {

   public void eat() {
      System.out.println("Cat Eats");
   }

   public void drink() {
      System.out.println("Cat Drinks");
   }

   public void printMessage(){
     super.eat();
     super.drink();
   }

  public static void main(String[] args) {
    Cat myCat = new Cat();
    myCat.eat();
    myCat.drink();
    myCat.printMessage();
 }
}
h_k
  • 1,674
  • 1
  • 24
  • 46
  • It will work, but simpler would be to change `Animal myAnimal = myCat;` to `Animal myAnimal = new Animal()` – Tzen Nov 05 '19 at 15:15
0

Please don't vote on this answer... you can vote on the other one :-) This is a bad answer, but shows how you would do what you are trying to do... poorly.

public class Main
{
    public static void main(final String[] argv) 
    {        
        Child  child;
        Parent parent;

        child  = new Child();
        parent = child;

        child.a();
        parent.a();
        child.otherA();
        parent.otherA();
    }
}

class Parent
{
    public void a()
    {
        System.out.println("Parent.a()");
    }

    public void otherA()
    {
        // doesn't matter what goes here... really should be abstract
    }
}

class Child
    extends Parent
{
    @Override
    public void a()
    {
        System.out.println("Child.a()");
    }

    @Override
    public void otherA()
    {
        super.a();
    }
}
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 5
    If you admit yourself it's a bad answer and shouldn't be used, it's probably better to just delete it. – Rob Apr 06 '17 at 05:48
  • 4
    Not really, it is there to show people what not to do. Anyone can come up with this, I wanted to let people know that if they did then they should throw it away. Hence my request to not vote on it at all... – TofuBeer Apr 06 '17 at 06:18
  • 7
    I think it would be better if this were a section of your accepted answer. – Jim Balter Apr 07 '17 at 04:22
0

Cat can't stop being a cat, even if it is an animal. Cat will eat and cat will drink in a cat's way. It might be similar to what an Animal does, which is why it overrides the method. If you want it to do what the animal does by default, don't override. You could probably do some weird stuff with reflection and make separate methods that access the parent methods such as:

public void superDrink() {
   Animal.class.getMethod("drink").invoke();
}

but that might be overkill don't you think?

Of course that probably wouldn't work since it's not static.

Michael
  • 41,989
  • 11
  • 82
  • 128
Jimi Kimble
  • 504
  • 5
  • 10
0
public class Main {
    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.eat();
        myCat.drink();
    
        Animal myAnimal = new Animal();
        myAnimal.eat();
        myAnimal.drink();
    }
}
    
public class Animal {
    public void eat(){
        System.out.println("Animal eat() called");
    }
    public void drink(){
        System.out.println("Animal drink() called");
    }
}
    
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("Cat eat() called");
    }
    
    @Override
    public void drink() {
        System.out.println("cat drink() called");
    }
}

OUTPUT:

Cat eat() called

cat drink() called

Animal eat() called

Animal drink() called

You need to create an object of the super class Animal OR another option is to use the keyword super in the child class methods e.g., super.eat() or super.drink()

Community
  • 1
  • 1
cNgamba
  • 111
  • 1
  • 10
0

You can do what you want with a few minor changes to your code. Naturally the methods of the Animal class have been overriden and you cannot simply access them by changing the reference type. Instead, you could slightly change the definition of the eat and drink functions as follows.

class Animal{
    public void eat(boolean randomBoolean){
        System.out.println("Animal eats");
    }
    public void drink(boolean randomBoolean){
        System.out.println("Animal drinks");
    }
}

class Cat extends Animal{
    public void eat(boolean wantOverriden){
        if(wantOverriden){
            boolean randomBooleanValue=true|false;
            super.eat(randomBooleanValue);
        }
        else{
            System.out.println("Cat eats");
        }
    }
    public void drink(boolean wantOverriden){
        if(wantOverriden){
            boolean randomBooleanValue=true|false;
            super.drink(randomBooleanValue);
        }
        else{
            System.out.println("Cat drinks");
        }
    }
}

Now you should be able to access the overriden methods of the Animal class through the Cat class object by simply passing in a boolean value indicating if you want to do so ex:

Cat c=new Cat();
c.eat(false);     //Indicating that you dont want to access the overriden method
c.drink(false);   //Indicating that you dont want to access the overriden method
c.eat(true);          //Indicating that you want to access the overriden method
c.drink(true);        //Indicating that you want to access the overriden method