This question already has an answer here:
Overloading method invoke issue
(1 answer)
Closed 1 year ago.
class Animal{
void eat(Animal animal){
System.out.println("animal eats animal");
}
}
public class Dog extends Animal{
void eat(Dog dog){
System.out.println("dog eats dog");
}
public static void main(String[] args) {
Animal a = new Dog();
Dog b = new Dog();
a.eat(b);
b.eat(b);
}
}
In the above code, the output will be
animal eats animal
dog eats dog
Why this happened?
Probably you expect to see twice "dog eats dog". This does not happen because the two methods have a different signature. Therefore, Dog#eat(Dog) does not override Animal#eat(Animal) but provides a more specific eat method instead.
If you add #Override to void eat(Dog dog) there will be an error. Using this annotation is good practice because it denotes that the annotated method should override a method declaration in a supertype. If the method does not do that (as in your example) you get the following error to make you aware if it:
Method does not override method from its superclass
If you want to override the eat method in Dog, you need to provide the same signature:
#Override
void eat(Animal animal) { // instead of eat(Dog dog)
System.out.println("dog eats dog");
}
It is simply because Java does not support contravariant parameters. On the other hand, it supports covariant return types.
Due to the support for covariant return types, a subclass override can have a more specific return type in the hierarchy while overriding the base class method, like the code below is valid:
class Animal {
protected Animal getAnimal() {
System.out.println("Animal");
return this;
}
}
class Dog extends Animal {
#Override
protected Dog getAnimal() {
System.out.println("Dog");
return this;
}
}
In the above example, you can observe that Dog.getAnimal() returns a more specific Dog instead of the base Animal but it is still considered an override because Java supports covariant return types.
On the other hand, if you do that with parameters:
class Animal {
protected void petAnimal(Animal animal) {
System.out.println("Petting Animal");
}
}
class Dog extends Animal {
#Override
protected void petAnimal(Dog dog) {
System.out.println("Petting Dog");
}
}
This is not an override but an overload.
Hence both the petAnimal() methods (one with Animal as parameter and another with Dog as parameter) are treated as two different methods. Remember, parameters are part of the method signature whereas return types are not.
The second example does not even work as the #Override annotation finds out that the method is not an override. Whenever you want to ensure that you override, use the #Override annotation, it will let you know if you are not overriding the method. #Override can also be used when implementing interfaces.
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
class Animal{
void eat(Animal animal){
System.out.println("animal eats animal");
}
}
public class Dog extends Animal{
void eat(Dog dog){
System.out.println("dog eats dog");
}
public static void main(String[] args) {
Animal a = new Dog(); //We use this when we don't know the exact runtime type of an object
//Parent can hold any child but only parent specific methods will be called.
Dog b = new Dog();
a.eat(b); //Parent method will be called i.e Animal.eat(...)
b.eat(b); //Dog Class method will be called i.e Dog.eat(...)
}
}
First of all, the eat() not being overridden in the child class Dog
Usually, method overloading doesn't necessarily need inheritance and can be achieved within the same class. However, in this code the eat() method is overloaded by child class Dog.
Overloaded methods are differentiated by the number and the type of the arguments passed into the method.
So, at compile time it always picks the most specific class implementation based on its type.
Related
Example program:
class Animal {
public void eat() {
System.out.println(" Animal eats");
}
class Dog extends Animal {
public void eat(String s) {
System.out.println(" Dog eats" + s);
}
public class Demo {
public static void main(String args[]){
Animal a = new Dog();
Dog d = (Dog) a;
a.eat();
d.eat("Meat");
}
}
My question is why a.eat("Meat") is not reachable? Since a is Object during the time it's referring to Dog Object, it should allow to call eat("meat").
Can anyone clarify where am I going wrong?
You're trying to call method of subclass Dog through variable of base class Animal.
Java has strong typing, so if you declare variable of class Animal you can access only to methods and fields of Animal and its superclasses.
You can call eat("Meat") from Animal using casting ((Dog) a).eat("Meat") but you should avoid as much as possible such constructions.
Btw, your approach looks like a function overloading rather than polymorphism.
P.S. Maybe this article about strong typing will be helpful for you. And this one about difference between overloading and polymorphism.
Dog d = (Dog) a;
Here you are casting the Animal a to a Dog. However, this does not change the type of a. a is still an Animal hence you can only call eat() without a string.
I have a Dog class described as:
class Dog {
//data members
void bark() {
//Bark Algorithm
}
}
Now in another class which has the main method and in the main method, if I do the following:
Object dog = new Dog();
dog.bark();
Shouldn't it work as the "dog" reference is holding a Dog instance? Why is this not valid?
The language used here is Java.
Thanks for the help in advance.
Java is very strongly typed. Java compiler performs a method check at compile time, not at runtime. dog is declared as Object, so compiler checks if Object class has a method named bark(). It doesn't, so it throws a compiler error. This is how Java is designed.
Note that this is not a limitation of polymorphism per se, but a limitation of the implementation of polymorphism in Java. This exact same code would perfectly compile (and work) in a more dynamically typed language like Groovy, which also runs on the JVM.
The class Object does not have a method called bark. Therefore, your code would not compile.
However, this does not mean that the compiler decides what method to call purely based on the reference type. Your reference type decides what methods you CAN call, while the instance type will decide what you method you WILL call. This is the essential mechanism for polymorphism.
For example,
class Animal
{
void makeSound()
{
//Generic animal sound algorithm
}
}
class Dog extends Animal{
void makeSound()
{
//Bark Algorithm
}
}
Then
Animal dog = new Dog();
Animal animal = new Animal();
dog.makeSound(); //calls bark
animal.makeSound(); //generic animal sound
I think I got the solution here. The compiler decides which function to call based on the reference type and not on the instance type that reference holds.
Like in this case, just like the Dog class, many other animals can also can be instantiated and Object references can be used to refer to their objects on the heap, but not all can bark(). Hence the compiler decides that the function call should be based on the reference type, rather than the instance type.
If you're sure about type of dog you can always do typecasting
Object dog = new Dog();
((Dog)dog).bark();
Safe version:
Object dog = new Dog();
if (dog instanceof Dog)
((Dog)dog).bark();
UPD
Polymorphism example:
interface Animal {
}
interface Barkable extends Animal {
void bark();
}
class Dog implements Barkable {
#Override
public void bark() {
System.out.println("woof-woof");
}
}
class Cat implements Barkable {
#Override
public void bark() {
System.out.println("meow");
}
}
class SilentCreature implements Animal {
}
....
Animal animal = new Dog();
animal.bark();
animal = new Cat();
animal.bark();
animal = new SilentCreature();
// new SilentCreature() returns new animal, but not Barkable
animal.bark(); // as Animal doesn't have method bark() this code won't compile
This question already has answers here:
Why bark method can not be called
(5 answers)
Closed 6 years ago.
The Superclass reference variable can hold the subclass object, but using that variable you can access only the members of the superclass, so to access the members of both classes it is recommended to always create reference variable to the subclass.
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
b.bark();
}
}
output:
TestDog.java:26: error: cannot find symbol
b.bark();
^
symbol: method bark()
location: variable b of type Animal
1 error
What I do not understand here is why is the object 'b' able to access the Dog.move() and not Dog.bark() because the statement mentioned above says it can access only the members of the superclass and not the subclass.Following this logic the output of b.move() should be "Animals can move" and not "Dogs can walk and run".But that is not case.Can anyone help me with this?Thanks in advance!
Congratulations - you just discovered polymorphism.
In Java the classes are bound dynamically. That is if you are invoking a method the implementation of the object is invoked (in your case the Dog) and not the method of the reference type (in your case the Animal).
This allows overwriting methods and replace or fulfill their implementation.
On the other hand, you can only access methods that are available in the type you are referencing, not the implementing type (in your case the Animal). To invoke the methods of the instance, you would have to use it as the reference type (in your case the Dog).
In your question Animal is a parent class which doesn't have bark() method so that method isn't overridden. If you were able to access bark() from parent class without declaring either abstract method or defining it, then that would be violation of the Polymorphism principle.
If you really want to access it that way, then you can either define a abstract public void bark(); in your parent or access that method by typecasting like this
((Dog) b).bark();
This will not compile since Animal does not have a method called bark.
Think of it this way, all dogs are animals, but not all animals are dogs. All dogs bark, but not all animals bark.
This code is wrong, as the line b.bark(); will give you a compiler error, because b is only defined as an Animal, which cannot bark().
If you change Animal b = new Dog(); to Dog d = new Dog(); it will work properly.
You've got inheritance mixed up. Dog can do what Animal can do, not vice versa.
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
#Override public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
public void moveSuper() {
super.move();
}
}
public class TestDog {
public static void main(final String args[]) {
final Animal a = new Animal(); // Animal reference and object
a.move(); // runs the method in Animal class
final Dog d = new Dog(); // Animal reference but Dog object
d.move(); // runs the method in Dog class
d.bark();
d.moveSuper();
}
}
I am familiar with type casting in inheritance model.
Let SuperClass and SubClass be parent and child classes;
SuperClass superClass = new SubClass(); -- Here the object instantiated is a subclass object;
but its reference type is SuperClass; that is only those methods of SuperClass can be called on the subclass object; Any methods that are not inherited/overridden in subclass cannot be called (that is any unique methods of subclass).
I observed same behavior as above if SuperClass is an interface and SubClass implements it. That is only those methods declared in SuperClass interface are available to be called on the SubClass object. Is my understanding correct? But with some casting, I can call methods that is not part of the interface, which I have observed in my sample code below;
I have made some comments on my understanding as how it works;
but I would like to know if that make sense or if my interpretation is wrong;
class Animals {
public void bark(){
System.out.println("animal is barking");
}
}
interface catIF {
public void catting();
}
interface dogIF {
public void dogging();
}
class Dog extends Animals implements dogIF {
public void bark(){
System.out.println("dog is barking");
}
public void dogging() {
System.out.println("dogging");
}
}
class Cat extends Animals implements catIF {
public void bark(){
System.out.println("cat is barking");
}
public void catting() {
System.out.println("catting");
}
}
public class Animal {
public static void main(String[] args){
dogIF dog = new Dog();
//dog.bark(); this fails
//This method actually actually exists;
//but it is not available or hidden because dogIF reference
//limits its availability; (this is similar to inheritance)
Dog dog2 = new Dog();
dog2.bark();
////prints dog is barking
Animals an =(Animals) dog;
an.bark();
//prints dog is barking
//by casting we mean, treat the dog as an animals reference
//but the object itself is a dog.
//call the bark() method of dog
//but dog did not have this method in the beginning (see first line
// in main - when instantiated with interface type)
}
}
Inheritance of interfaces really isn't "flaky" or complicated. They behave exactly the way abstract classes do, with the exceptions that you reference them differently (implements rather than extends) and that you're allowed to inherit as many interfaces as you like but can only have one superclass (abstract or not).
As with other inheritance: If all you know about an object is that it implements an interface, then you can only access it through that interface. If you know that it implements another interface, or a specific superclass, or is an instance of a particular class, then you can cast it to those and access it through the exposed members of those.
So, yes: If all your program knows is that the object is an instance of Animals, then all you can do is call what's declared on Animals. That means bark() plus whatever methods it inherits from Object (since everything is an Object directly or indirectly even if that isn't explicitly stated).
If your program knows that the object is an implementation of dogIF or catIF -- because the variable type says it is, or because you've successfully typecast it to one of those interfaces -- you can also call the method(s) declared by those interfaces. By the way, the usual convention for interfaces is to name them like classes, with UppercasedFirstLetter... since in many cases the difference between an interface and a class really isn't significant to the folks using it.
If your program happens to know that the object is a Dog, you can call anything it inherits from either Animals or dogIF, or that is provided directly by Dog. Of course it could actually be a Chihuahua (subclass of dog), but that's OK, the subclass will respond to anything the superclass would have responded to, in "the right way to maintain the semantics". (That is, a Chihuahua may respond to bark() by saying "yip yip yip grr yip!", but that method really shouldn't cause it to try to bite your ankle.)
Hope that helps. It really isn't that complicated.
I have some question about upcast/downcast.
I created an abstract super class Animal, subclass Dog and subclass BigDog. and I also give abstract method in Animal, and override it in Dog and BigDog.
abstract public class Animal {
abstract public void greeting();
}
public class Dog extends Animal {
#Override
public void greeting() {
System.out.println("Woof!");
}
}
public class BigDog extends Dog {
#Override
public void greeting() {
System.out.println("Woow!");
}
}
now my test code:
public class TestAnimal {
public static void main(String[] args) {
Animal animal2 = new Dog();
Animal animal3 = new BigDog();
// Downcast
Dog dog2 = (Dog) animal2; //cast Animal class to Dog class, legit
BigDog bigDog2 = (BigDog) animal3; //cast Animal to BigDog, legit;
Dog dog3 = (Dog) animal3; //Animal Class contains BigDog cast into Dog?
dog2.greeting();
dog3.greeting(); //in which class the method is called?
}
}
I understand the relationship between superclass/subclass and how cast works. My question is, however, can you cast a superclass into a specific subclass, knowing there's a class in between? for example, if I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?
in short, you can certainly say a superclass object is a subclass object, but why can you invert?
On second thought,
I'm guessing this: I'm asking JVM cast an Animal class reference to Dog and link the new Dog reference to the BigDog object, rather than really casting the BigDog object.
So I can invoke all Dog and Animal methods on that Dog reference (to BigDog), but none of the BigDog methods, unless it was overridden in BigDog.
What Java checks when invoking a method is: if the reference (DOG) has the reference, and if the object(BigDog) has an override. if not, Dog method is called, otherwise, BigDog method is called.
Can anyone confirm my guess?
You can always cast to a specific subclass, unless the compiler is smart enough to know for certain that your cast is impossible.
The best way to cast to a subclass is to check if it can be done:
if ( doggy instanceof BigDog ) {
doSomethingWithBigdog( (BigDog) doggy );
} else if ( doggy instanceof SmallDog ) {
doSomethingWithSmalldog( (SmallDog) doggy );
} else {
// Neither a big dog nor a small dog
}
...
private void doSomethingWithBigdog( BigDog dog ) {
...
}
private void doSomethingWithSmalldog( SmallDog dog ) {
...
}
Keep in mind that casting is evil. Sometimes necessary, but often (not always) it can be designed away by implementing methods on the base class, or by not assigning a Dog to an Animal variable but to keep it a Dog.
If I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?.
Simply you will get compiler error.Since you can't call a method that is not declared in parent and declared in child class using parent reference
There is no method whose signature will match with these method calls :
dog2.greeting(dog3);
dog3.greeting(dog2);
so, Its pretty much a compilation failure.
You need to know about Dynamic Method Dispatch.
here are few links 1,2,3 go through them.
First correct the source code, so it will compile. The proper usage of the methods: dog2.greeting(); and dog3.greeting(); or add method public void greeting(Animal animal);.
dog3.greeting(); - invoking method greeting() for dog3. dog3 has the same reference as animal3. animal3 has reference of BigDog so method greeting() is invoked to the class BigDog and the output is Woow!
When you inherit Dog from class Animal, then class Dog have all methods from class Animal.