How to call the overridden method of a superclass?

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

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 :-)


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");
    }
}

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();
    }
}

  • 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.