It's based on the concept of Inheritance and Polymorphism
Overriding happens when the sub-class has the same signature methods as that of the superclass. In your code, in the below subclass *method, the parameter being passed is a Dog type object and in the superclass i.e Animal, the parameter passed is an Animal type object.
void eat(Dog dog){
System.out.println("dog eats dog");
}
So you can change the above method as below to see the overriding effect: -
void eat(Animal dog){
System.out.println("dog eats dog");
}
As suggested by @Mat, it's best to use @Override annotation because it will help the java compiler to find the issue at the compile time itself.
Below I'm trying to explain the concept of how inheritance and polymorphism are working once you change the signature of the eat method in Dog class: -
Inheritance is a way to base one class on another class, like a template built from an existing template. You could create a class called 'Dog' that acts as a template for all Dog objects. We could then create another class called 'Animal' that is a parent class of our 'Dog' class. All Dogs are animals, but not all animals are dogs. Our Animal class could define functionality for all Animals and then the Dog class could take all this functionality, without re-writing it, by extending/inheriting from the Animal class. The Dog class could then add more functionality, more variables, and methods, that are specific only to Dog objects.
The Dog class extends the Animal class, this is inheritance. The Dog class is overwriting the Animal class eat method.
When we say Animal a = new Dog();, we declare a variable a that is declared as an Animal type, but it initialized as a Dog object. This is polymorphism. Because the Dog extends from the Animal class, we can treat it as an Animal, and declare it as an Animal variable type. We cannot do the reverse, because the Animal class does not extend from the Dog class (not all Animals are dogs)
This is because the a variable is being treated as an Animal data type. This is why you will be able to access all the Animal class methods but the methods with the same signature as Dog will be overridden by the implementation from the Dog class. Remember, the left side of the equals '=' symbol is the declaration and the right side is the initialization.
Also, that's why when you declare Dog b = new Dog(); and call the eat() method it calls the implementation from the Class Dog and not Animal as it's explicitly mentioned as object type Dog