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.
Related
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.
I am working with an API in my company where I would like to create a subclass for an existing object. Here are the caveats:
I cannot modify the superclass
I cannot modify how the superclass object is instantiated
The example I see most commonly is a Dog as a subclass of Animal, so I will use that. Let's say you have this class in the API:
//API class, which I cannot modify
public class Animal(){
public void eat(){
//All animals can do this
}
}
Now I would like to create a class like this, which adds a few methods to Animal.
//My subclass, which I can modify
public class Dog extends Animal(){
public void fetch(){
//Only dogs can do this
}
}
So now let's say I have an instance of Animal (one that is not a Dog). I essentially need to downcast it into a Dog. I get that downcasting is not directly supported in Java, but is there any workaround for this?
public class AnimalExample{
public static void main(String[] args){
Animal animal = MyApi.getAnAnimal();
//Dog dog = (Dog) animal; ---throws a runtime error
Dog dog = Dog.getDog(animal); //Maybe something like this?
//Then I should be able to call both eat() and fetch()
dog.eat();
dog.fetch();
}
}
Again, I understand that downcasting is not directly supported. But there has to be some workaround for this, and I can't figure it out. I know that I could use a wrapper class (eg DogWrapper), but that would be a little more difficult than I'd like because I still frequently call the dozens of superclass methods.
UPDATE: I understand that it's not yet a Dog, but I was wondering if there was a way to convert it into a Dog. It basically sounds like, from what people are saying, that I either have to convert it manually (copy each attribute/method over one-by-one) or just use a Wrapper class. A Wrapper class seems a lot less messy, so unfortunately I'll just have to go that route. So DogWrapper will have a fetch() method and a getAnimal() method. So if I want the Dog to eat, then I have to call dog.getAnimal().eat(). I was avoiding having to do that, but I guess there's no way around it. Does anyone see anything simpler than that?
You can have a constructor which takes Animal and instantiates the Dog part of the object with defaults or as required.
public Dog (Animal animal) {
super(); // any instantiation that has to be done for animal
// Dog instantiation
// Use animal properties as required
}
Dog dog = new Dog(animal);
Also having a static method as you mentioned Dog.getDog(animal) is an option, depends on your coding preference.
Let's suppose I create a method that requires a Dog, but is meant to extend the Animal API. Sure, I could just make the signature like so:
public void doFetch(Dog dog)
But as I said, I want to extend the Animal API. Now, if the given Animal is not a Dog, I can't fetch. With that in mind, I can do the following:
public void doFetch(Animal fetcher) {
if(fetcher instanceof Dog) {
Dog dog = (Dog) fetcher;
... //Do fetchy things
return;
}
//If we reach this point, then the animal is not a dog
throw new IllegalArgumentException("fetcher is not a Dog!");
}
Now let's suppose, as in your case, I have an Animal that is not a dog, but I want it to be a Dog for some reason. In this case, I could convert any Animal into a dog using some kind of translator. I prefer to define things like this as static methods in the Dog class itself:
//Breaks the laws of nature by making a Dog from any Animal.
public static Dog fromAnimal(Animal animal) {
Dog dog = new Dog();
//Here you would set all the properties of the animal, e.g.:
dog.setName(animal.getName());
...
return dog;
}
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();
}
}
Using this as an example:
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 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
}
}
Is it right here to say upon calling b.move() the method "move() under the Dog class" has overridden the "move() under the Animal class" as the Dog object takes precedence when calling the same method when referenced by an Animal type?
Ive noticed many websites don't explain this, rather they just throw out examples without talking through the stuff line by line. Just want to clear up my terminology confusion.
A side note, would it be possible to have a Dog object but invoke move() which is under the Animal class? for example having something like:
Dog doggy = new Dog();
doggy.move()
>>>
Animals can move
>>>
Would this be possible? would ((Animal) doggy).move() accomplish this?
Absolutely, it is correct to say upon calling b.move() the method "move() under the Dog class" has overridden the "move() under the Animal class".
For the second question, you should implement the class Dog as:
public class Dog extends Animal {
public void move(){
super.move();
}
}
For the third question, the answer is "NO".
((Animal) doggy).move()
This is simply 'redundant' and give the output "move() under the Dog class".
You can do it like this
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 moveParent() {
super.move();
}
}
public class Main{
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
Dog doggy = new Dog();
doggy.moveParent();
}
}
Use super keyword to call upon the parents member functions or data members.
like: super.move(); in this case you parent function will be called.
From the oracle docs
If two or more independently defined default methods conflict, or a default method conflicts with an abstract method, then the Java compiler produces a compiler error. You must explicitly override the supertype methods.
So basically, if you're in the sub-class calling a method which is in the superclass, you won't be able to call the super-class' method unless you use super.function(). Read up more on it here
It's principle object oriented programming (aka OOP) - polymorphism. Dog, Cat, Elephant are all animal.
Animal d = new Dog();
Animal c = new Cat();
Animal t = new Tiger()
It must not care about, always right. :)
public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
The assignment Dog dog = (Dog) animal; does not generate a compilation error, but at runtime it generates a ClassCastException. Why can't the compiler detect this error?
By using a cast you're essentially telling the compiler "trust me. I'm a professional, I know what I'm doing and I know that although you can't guarantee it, I'm telling you that this animal variable is definitely going to be a dog."
Since the animal isn't actually a dog (it's an animal, you could do Animal animal = new Dog(); and it'd be a dog) the VM throws an exception at runtime because you've violated that trust (you told the compiler everything would be ok and it's not!)
The compiler is a bit smarter than just blindly accepting everything, if you try and cast objects in different inheritence hierarchies (cast a Dog to a String for example) then the compiler will throw it back at you because it knows that could never possibly work.
Because you're essentially just stopping the compiler from complaining, every time you cast it's important to check that you won't cause a ClassCastException by using instanceof in an if statement (or something to that effect.)
Because theoretically Animal animal can be a dog:
Animal animal = new Dog();
Generally, downcasting is not a good idea. You should avoid it. If you use it, you better include a check:
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
In order to avoid this kind of ClassCastException, if you have:
class A
class B extends A
You can define a constructor in B that takes an object of A. This way we can do the "cast" e.g.:
public B(A a) {
super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A
// If B class has more attributes, then you would initilize them here
}
Elaborating the answer given by Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Here you are saying to the compiler "Trust me. I know d is really referring to a Dog object" although it's not.
Remember compiler is forced to trust us when we do a downcast.
The compiler only knows about the declared reference type. The JVM at runtime knows what the object really is.
So when the JVM at the runtime figures out that the Dog d is actually referring to an Animal and not a Dog object it says.
Hey... you lied to the compiler and throws a big fat ClassCastException.
So if you are downcasting you should use instanceof test to avoid screwing up.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Now a question comes to our mind. Why the hell compiler is allowing the downcast when eventually it is going to throw a java.lang.ClassCastException?
The answer is that all the compiler can do is verify that the two types are in the same inheritance tree, so depending on whatever code might have
come before the downcast, it's possible that animal is of type dog.
The compiler must allow things that might possible work at runtime.
Consider the following code snipet:
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
However, if the compiler is sure that the cast would not possible work, compilation will fail. I.E. If you try to cast objects in different inheritance hierarchies
String s = (String)d; // ERROR : cannot cast for Dog to String
Unlike downcasting, upcasting works implicitly because when you upcast you are implicitly restricting the number of method you can invoke,
as opposite to downcasting, which implies that later on, you might want to invoke a more specific method.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Both of the above upcast will work fine without any exception because a Dog IS-A Animal, anithing an Animal can do, a dog can do. But it's not true vica-versa.
To develop the answer of #Caumons:
Imagine one father class has many children and there is a need to add a common
field into that class. If you consider the mentioned approach, you should
go to each children class one by one and refactor their constructors for the new field.
therefore that solution is not a promising solution in this scenario
Now take a look at this solution.
A father can receive an self object from each children. Here is a father
class:
public class Father {
protected String fatherField;
public Father(Father a){
fatherField = a.fatherField;
}
//Second constructor
public Father(String fatherField){
this.fatherField = fatherField;
}
//.... Other constructors + Getters and Setters for the Fields
}
Here is our child class that should implement one of its father
constructor, in this case the aforementioned constructor :
public class Child extends Father {
protected String childField;
public Child(Father father, String childField ) {
super(father);
this.childField = childField;
}
//.... Other constructors + Getters and Setters for the Fields
#Override
public String toString() {
return String.format("Father Field is: %s\nChild Field is: %s", fatherField, childField);
}
}
Now we test out application:
public class Test {
public static void main(String[] args) {
Father fatherObj = new Father("Father String");
Child child = new Child(fatherObj, "Child String");
System.out.println(child);
}
}
And here is the result :
Father Field is: Father String
Child Field is: Child String
Now you can easily add new fields to father class without being worried of your children codes to break;
The code generates a compilation error because your instance type is an Animal:
Animal animal=new Animal();
Downcasting is not allowed in Java for several reasons.
See here for details.
As explained, it is not possible.
If you want to use a method of the subclass, evaluate the possibility to add the method to the superclass (may be empty) and call from the subclasses getting the behaviour you want (subclass) thanks to polymorphism.
So when you call d.method() the call will succeed withoug casting, but in case the object will be not a dog, there will not be a problem
As it was said before, you can't cast from superclass to subclass unless your object was instantiated from the subclass in the first place.
However, there are workarounds.
All you need is a set of constructors and a convenience method that will either cast your object to Dog, or return a new Dog object with the same Animal properties.
Below is an example that does just that:
public class Animal {
public Animal() {}
public Animal(Animal in) {
// Assign animal properties
}
public Dog toDog() {
if (this instanceof Dog)
return (Dog) this;
return new Dog(this);
}
}
public class Dog extends Animal {
public Dog(Animal in) {
super(in);
}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = animal.toDog();
}
}