Below is the sample code
class Animal {
void makeNoise() {System.out.println("generic noise"); }
}
class Dog extends Animal {
void makeNoise() {System.out.println("bark"); }
void playDead() { System.out.println("roll over"); }
}
class DogTest {
public static void main(String [] args) {
Animal animal = new Animal();
Dog d = (Dog) animal;
d.makeNoise();
}
}
Above code compiles well but when i try to run it, i get
java.lang.ClassCastException
My assumption is it should print "generic noise" because at run time it should invoke actual Animal object makeNoise() method without giving any exception.
You can't cast an arbitrary Animal instance to a Dog instance, unless the instance you are casting is actually a Dog or a sub-class of Dog.
It would make more sense for the Animal class to be abstract, since an actual Animal that can be instantiated should be a specific Animal, such as Dog, Cat, etc...
All answers here are technically correct. But I want to explain this from an other point of view.
First off, you have defined one Animal and one Dog. So far everything is fine. The problem comes when you (within DogTest) create an Animal and cast ti as Dog. Why? Not every Animal is a Dog. I mean, an Animal can be a Bird, a Cat, an Elephant... These Animals do not "bark". Said that, you do can cast a Dog as an Animal because all Dogs are Animals.
I hope I have clarified a bit your mind :)
If you had:
Animal animal = new Dog();
Dog dog = (Dog) animal;
there would be no problem.
You need to understand the difference between compile-time type and runtime type. In the code snippet above, the compile-time time of animal is Animal, while the runtime type is Dog. This is why there's no problem casting to Dog (note that the actual casting happens at runtime).
In your code, however, the runtime type of animal is Animal (same as the compile-time type). This means that the animal will point to an object on the heap, that supports the features of an Animal (which is makeNoise()), but not the features of a Dog and that's why the ClassCastException happens.
It won't print anything, because you won't reach the line with d.makeNoise(). The java.lang.ClassCastException is thrown in the earlier line, when you try to cast to Dog something, which is not Dog.
Still, without this line, you'll get the expected result: "generic noise".
Best possible downcasting i can explain by re-writing your code as follows :-
public interface Animal {
public void show();
}
public abstract class Dog implements Animal {
public void display(){
System.out.println("Dog Called");
}
}
public class Impl extends Dog{
#Override
public void show() {
System.out.println("Impl Called");
}
}
class DogTest {
public static void main(String [] args) {
Animal a = new Impl();
/**
* child class's method tried to be accessed with the help of
* parent class's object using downcasting of object
* */
((Dog)a).display();
}
}
However real time such requirements can fulfilled without using explicit downcasting of objects instead with the help of Factory Design Pattern in which we create object without exposing the creation logic to the client and refer to newly created object using a common interface.
Complete factory pattern can be pulled from here
Related
I am still new to Java, and I am a bit confused with how Java is treating a superclass variable that is referencing a subclass reference.
I have two classes:
public class Animal{
}
public class Dog extends Animal{
}
And then I created a Run class as below:
public class Run{
public void get_dog (Dog a){
System.out.println("got a dog");
}
public static void main(String[] args) {
Animal a_animal = new Dog(); //Create a Animal variable with Dog class
Run test = new Run();
System.out.println(a_animal.getClass().getSimpleName());
test.get_dog(a_animal); //This will not run
}
}
The getClass().getSimpleName() tells me that a_animal's class is Dog. But the test.get_dog(a_animal) will not run, saying get_name() will only take a Dog class instead of a Animal class. So what exactly is the class for a_animal?
The confusion here is one of static typing versus dynamic typing. At compile-time, the a_animal variable is known to the compiler as an Animal. Trying to use it as a Dog fails because the compiler knows that not all Animal instances are dogs (i.e. Animal is not Dog, and is not a subclass of Dog).
At runtime, the a_animal will reference a Dog, and that call would work. To see how this plays out, change test.get_dog(a_animal) to test.get_dog((Dog) a_animal) - this (Dog) is a cast that tells the compiler to treat a_animal as a Dog type.
Try this:
test.get_dog((Dog)a_animal);
the get_dog() method is expecting a Dog object as the parameter. Since your a_animal is first initialized as a Animal class, you need to explicitly typecast it as a Dog object, so that it knows that your a_animal is a Dog object.
Check out: Polymorphism and Type casting in Java
As per your code you should pass an Animal object to get_dog method and not a Dog object. What you have tried is called upcasting . A reference variable of Parent class refers to the object of Child class as below.
Animal a_animal = new Dog();
I've re-written you a code to understand the concept as below
public class Animal {
void run() {
System.out.println("An animal is running");
}
}
public class Dog extends Animal {
void run() {
System.out.println("Dog is running in 20kmph");
}
}
public class Run{
public static void main(String[] args) {
Animal a_animal = new Dog(); //Creating a reference variable of Animal class by referring to Dog class (upcasting)
a_animal.run();//
}
}
Below is the result
Explanation
We are calling the run method by the reference variable of Parent class. Since it refers to the subclass object and subclass method overrides the Parent class method, the subclass method is invoked at runtime.
The method invocation is determined by the JVM and not the compiler, it is known as runtime polymorphism.
Suppose I have 3 classes:
The super class is: Animal
There is 1 subclass Dog that inherits Animal
There is 1 subclass Cat that inherits Animal
Now if I do this: Animal a = new Dog();
Does the object Dog that a points to get casted to Animal?
If yes then does this cast both the variable and the object to dog?
((Dog)a).bark(); // bark() is specific for the Dog
Also what are the rules for casting these reference types in Java?
I will try to describe what happens in the background, in the hopes that it will clear some things.
Lets break this declaration & definition into parts.
'a' is declared as an Animal.
'a' is defined as a Dog.
Dog extends Animal, therefore, animal methods (including constructor) get defined.
Dog's methods get defined, whilst overriding any method that was defined by the parent class Animal) and overshadowing member variables of the parent class.
When looking at 'a', you are using the 'Animal' perspective and for that reason you are not capable of using any methods (or fields) declared only by sub-classes of Animal. In order to "gain" that perspective you can downcast from Animal to Dog exactly as you did. Keep in mind that downcasting is not safe whereas upcasting is.
For example:
Animal a = new Cat(); // cats can mew
Animal b = new Dog(); // dogs can bark
(Dog)b.bark() // Unsafe but compiles and works.
(Dog)a.bark() // Unsafe but compiles and throws a run time exception.
In general, a good practice would be to create an abstract class for an Animal and then override some of it's methods with subclasses.
For example:
public abstract class Animal {
abstract void makeNoise();
}
public class Dog extends Animal {
void makeNoise(){
System.out.println("bark");
}
}
public class Cat extends Animal {
void makeNoise(){
System.out.println("mew");
}
}
I don't get what I'm creating actually...
Usually you create an object with dog speedy = new dog();
you call the constructor dog() which creates a dog object and speedy is the name of the reference to it. but what if the first dog is named "animal" (dog extends animal) ?
Your question isn't very clear, but if your Dog class is extending Animal, and you want to use the Dog methods/fields, you need to create a new Dog. You could create an Animal a = new Dog() but you still won't be able to access the Dog methods/fields (although it shouldn't throw an error)
Static vs dynamic type of an object
Consider the following classes:
class Animal {
void eat() { System.out.println("Nom nom"); }
}
class Dog extends Animal {
void eat() { System.out.println("I want a bone"); }
void bark() { System.out.println("WOOF"); }
}
Now consider the following code:
Animal dog = new Dog();
Question: what is the type of the variable dog? The answer depends on whether you want to know the static type or the dynamic type.
Static type is the type the compiler sees, which is Animal in this case. This is also the type of the variable. This will define which methods are available.
Dynamic type is the type that is defined at runtime, it is the "real" type of the variable, which defines its behaviour.
In the above code you will not be able to call bark() on variable dog, because its static type is Animal. However, when you call eat(), it will return I want a bone because its behaviour is defined by its dynamic type which is Dog.
In many cases you do not know the dynamic type of an object. For example if you write a method that has a parameter of type List, the actual dynamic type will be known only when someone calls your method with a List implementation (such as ArrayList, LinkedList etc.).
This depends on the way in which you would like to use your dog object. Consider this example:
class Animal {
public void eat() {
System.out.writeln("nam nam nam");
}
public void sleep() {
System.out.writeln("zzzz zzzz");
}
}
class Dog extends Animal {
public void bark() {
System.out.writeln("ruff ruff");
}
}
If you want to treat your dog like the rest of the animals, i.e. as someone who can eat and sleep, you do this:
Animal fifi = new Dog();
fifi.eat(); // Works fine
fifi.sleep(); // Works fine
fifi.bark(); // Compile error!
However, Fifi cannot bark. If you do this, on the other hand,
Dog speedy = new Dog();
speedy.eat();
speedy.sleep();
speedy.bark();
your Dog would be able to bark, in addition to also being able to eat and sleep, like the rest of the animals.
I want to understand the use-case of setting a parent reference to a child object.
Example: Dog class extends Animal class. (No interfaces, mind it)
I would normally create an object of Dog like this:
Dog obj = new Dog();
Now, since Dog is a subclass of Animal it already has access to all of Animal's methods and variables. Then, what difference does this make:
Animal obj = new Dog();
Please provide a proper use-case with an code snippet of its use. No theoretical articles about 'Polymorphism' or 'Coding to interfaces' please!
Code:
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Dog();
Dog obj2 = new Dog();
obj1.shout(); //output is bark..
obj2.shout(); //output is bark..
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Dog extends Animal{
public void shout(){
System.out.println("bark..");
}
}
class Lion extends Animal{
public void shout(){
System.out.println("roar..");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh");
}
}
Output is the same for both the cases. Then why do we set parent reference to child object?
Let me code some time.
List<String> list = new ArrayList<String>;
list.doThis();
list.doThat();
Oh wait ..I'm gone mad. I want to use LinkedList instead of ArrayList
List<String> list = new LinkedList<String>;
list.doThis();
list.doThat();
Yup, I have to change only declaration part. No need to touch all of my code. Thanks to programming to interfaces and with super classes.
This is an implementation of a principle which says -
Program to an interface, not to an implementation.
As an example, if you design a method to accept a reference of type Animal, then in future you can easily pass an= Cat implementation to it (provided of course that the Cat is a sub-type of Animal.
Which means -
public void doSomethingWithAnimal(Animal animal) {
// perform some action with/on animal
}
is much more flexible than -
public void doSomethingWithAnimal(Dog d) {
// your code
}
because for the first method, you can easily do something like -
doSomethingWithAnimal(new Cat());
if you ever decide to create new Cat type, inheriting from Animal.
Think generally, you will know java casting/oop concept.
Dog is a type of Animal so you can assign it to an animal.
But you can't assign Animal to a Dog. Because it can be any other animal like Cat. If you are sure the object is Dog, you can caste that to Animal. If the Animal is of type Dog then you cannot magically cast to a Goat.
Although there are some good answers (among the "meh" ones), it seems like none was acceptable for you. Maybe they are too theoretical or contain details that you are not interested in. So another try:
For the example that you described, it does not matter. If you really only have a two-line method like
void doit()
{
Animal x = new Dog();
x.shout();
}
then you could also have written
void doit()
{
Dog x = new Dog();
x.shout();
}
and this would not have a direct disadvantage.
One could even generalize this statement: For a reference that is only used locally, it does not matter. When you declare the reference in the method, and only use this reference in this method, and do not pass it to other methods, then there is no direct advantage in declaring it as Animal instead of as Dog. You can to both.
But...
even if you are not interested in this, I can't omit it:
... using the parent type is part of a best practice:
You should always use the least specific type that is sufficient for what you want to do
This has various technical reasons, regarding abstraction, generalization, flexibility, the application of polymorphism, and one could even go so far to call it a sort of "type hygiene".
And this explicitly also refers to the case where the reference is only used locally: If you don't want to call methods that are specific for the type Dog, but only want to call methods from the Animal class, then you should make this clear by declaring the variable as an Animal - simply because that's the least specific type that you need. So there is an indirect advantage of using the type Animal in these cases - namely that it is clear that the following code will only use methods of the Animal class, and none of the Dog class.
One could continue and go very far with further justifications, use case examples and technical details here. But for this, you may refer to the other answers, or some intermediate or advanced texbooks and tutorials.
Okay. I think I got my answer.
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Horse();
Horse obj2 = new Horse();
obj1.shout(); //output is neigh..
obj2.shout(); //output is neigh..
obj1.winRaces(); /*But this is not allowed and throws compile time error,
even though the object is of Animal type.*/
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh..");
}
public void winRaces(){
System.out.println("won race..");
}
}
So, when we use parent reference for child class object, we cannot access any specific methods in child class (that are not present in parent class) using that object.
This would be when you want the code that you're writing to work against the Animal interface instead of the Dog implementation. Creating an object in this way makes your code more robust in the long term.
I frequently use:
List<Object> aList = new ArrayList<>();
This is important when defining class level variables, because you want your whole object to work even if you change an unimportant detail later.
When you start with such a simple example, you can't see any benefits because you have tightly coupled the variable to the actual type of object it will hold.
Polymorphism comes into its own only when you consider method declarations where the parameter is of the least specific type needed by the method's implementation: then you can call it with any subtype and the method will know what to do with it, even though it has no knowledge of the actual object type. That's the essence of Liskov substitutability of types.
So imagine you have a method
int getAge(Animal a) {
return Days.toYears(currentDate() - a.dateOfBirth());
}
The method will work against any Animal, even those you defined after defining the method.
But, if you happen to understand the above, yet ask specifically why one would write
Animal a = new Dog();
then it still often makes sense: you promise up-front that you won't refer to any dog-specific aspects of the instance. Typically you'll see
List<String> strings = new ArrayList<>();
and in this case we know that the rest of the code doesn't rely on the specific choice of ArrayList as list implementation. This is a much smaller difference than the one decribed above, but it's a combination of brevity, safety, and custom which makes it stick.
Looking at the question:-
Polymorphism in java: Why do we set parent reference to child object?
In a method like below(Factory Pattern):-
public Animal doSomething(String str){
if(str.equals("dog")){
return new Dog();
}
else if(str.equals("cat")){
return new Cat();
}
else {
return new Animal();
}
}
You get a type of Animal and actual object of either Dog or Cat so calling a method of Animal will call the method overridden in actual Object of either Dog or Cat if the called method is overridden in base class. It provides you with the flexibility at run time to decide which method to run depending on the actual object and overridden method in base class if any.
The complete example is as under :-
package com.test.factory;
public class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
package com.test.factory;
public class Dog extends Animal{
#Override
public void shout(){
System.out.println("bark..");
}
}
package com.test.factory;
public class Horse extends Animal{
#Override
public void shout(){
System.out.println("neigh");
}
}
package com.test.factory;
public class Lion extends Animal{
#Override
public void shout(){
System.out.println("roar..");
}
}
package com.test.factory;
public class AnimalFactory {
public Animal createAnimal(String str){
if(str.equals("dog")){
return new Dog();
}
else if (str.equals("horse")){
return new Horse();
}
else if(str.equals("lion")){
return new Lion();
}
else{
return new Animal();
}
}
}
package com.test.factory;
package com.test.factory;
public class Polymorphism {
public static void main(String[] args){
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.createAnimal("dog");
animal.shout();
animal = factory.createAnimal("lion");
animal.shout();
animal = factory.createAnimal("horse");
animal.shout();
animal = factory.createAnimal("Animal");
animal.shout();
}
}
Output is :-
bark..
roar..
neigh
Parent animal's shout
The AnimalFactory has a createAnimal method which returns Animal. Since Dog, Lion and Horse are all animals. So we are able to create Dog, Lion and Horse objects by using Animal return type. What we achieved using Animal return type is
Animal animal = new Dog();
Animal animal = new Lion();
Animal animal = new Horse();
which is not possible without the Animal return type.
If I use return type as Dog in createAnimal method then it cannot return Lion or Horse and like wise.
I am refactoring a huge if statement I have. One of the ways I found to improve it was by using polymorphism and inheritance. In a very simplified way, this is what I have in my code:
public abstract class Animal {
public abstract void doAction();
}
public class Dog extends Animal {
public void doAction() {System.out.println("run");}
}
public class Cat extends Animal {
public void doAction() {System.out.println("sleep");}
}
public class RunActions {
public void runAction(Dog d) {
d.doAction();
}
public void runAction(Cat c) {
c.doAction();
}
}
public class Start {
public static void main(String args[]) {
Animal animal = new Dog();
new RunActions().runAction(animal); // Problem!
}
}
I know, I know. I could just call animal.doAction();. Or add a method in RunActions that receives Animal as a parameter.
But why doesn't the compiler allow me to call that last "runAction(animal)" line? Shouldn't the JVM figure out animal is an instance of Dog in runtime?
Is there an specific reason why it doesn't allow me to do that?
EDIT: Forgot to make Dog and Cat extend Animal. Fixed.
The compiler can't guarantee that there is an appropriate method at runtime.
You have a method that takes a Cat and you have a method that takes a Dog. You are trying to pass an Animal variable that references a Dog. What if would reference an Elephant? Then there would be no suitable method at runtime. That's why it won't let you compile.
Animal animal = new Elephant();
new RunActions().runAction(animal); // real problem now!
The main underlying concept that makes what you want impossible is that Java is a single-dispatch language, just like almost all other languages called "OOP". What this means is that the runtime decision which method to call takes into account only the first method argument, which is syntactically placed before the dot, the one whose value will be bound to the this special variable.
You may also wonder why single dispatch is used in most languages... this has to do with the basic idea of encapsulation and objects being owners of their methods. Consider your case: should runAction belong to RunActions or Animal? It belongs to both equally; better stated: it doesn't belong to either. This brings about a completely different programming model, one without encapsulation.
First of all, Dog and Cat should extend Animal:
public class Dog exttends Animal{
#Override
public void doAction() {System.out.println("run");
}
And use:
public class RunActions {
public void runAction(Animal a) {
a.doAction();
}
}
As both Dog and Cat are Animals, you can use Animal argument.
The problem is not all Animals may be Cats or Dogs. Consider:
public class Fish implements Animal{
public void doAction() {System.out.println("swim");
}
What would you expect your RunActions class to do?
That's why the compiler is complaining.
There are a few approaches you can use to make your situation work. The simplest is to have one method that accepts Animal and use a series of instanceof tests to figure out what you want to do with each specific subclass of Animal.
Better do following
public interface Animal {
public void doAction();
}
public class Dog implements Animal{
public void doAction() {System.out.println("run");
}
public class Cat implements Animal{
public void doAction() {System.out.println("sleep");
}
public class RunActions {
public void runAction(Animal d) {
d.doAction();
}
}
public class Start {
public static void main(String args[]) {
Animal animal = new Dog();
new RunActions().runAction(animal);
}
}
Firstly, you are not extending Animal in Dog and Cat. So do that first.
In inheritance ISA principal gets followed.
so for example
public class Dog extends Animal
here Dog extends Animal so that DOG IS ANIMAL but the reverse is not true ANIMAL CANNOT BE NECESSARILY A DOG. IT CAN BE CAT ALSO IN YOUR CASE.
So when you pass a reference of animal to the method which accepts a DOG or a CAT assignment would be something like
Dog d=animal;
which is read as animal is DOG and that is not true.
So compiler will not allow you to do that.
And regarding why Java doesn't allow that thing to be done is to achieve the features that it is capable of achieving.
Say for example, Java allows you to pass the animal object to the method and allows you to execute the method.
so in that case
Animal animal=new Dog();
Dog d= animal;
d.doSomething(); // let's say java allowed this no problem since animal is DOG.
BUT,
Animal animal=new Horse();
Dog d= animal;
d.doSomething(); // Can you imagine what will happen in this case?
So to avoid such situaltion java is intelligent enough to stop you when you are doing wrong. Hope this clears your doubt and help you to understand this.