I'm learning Java and can't understand some tricks of inheritance.
Example:
we have a class Animal;
we have a class Cat, extends Animal;
we have a class Tiger, extends Cat;
Questions:
1) Why Cat uses Tigers method?
See below example of "make_a_sound" method. It's from Tiger, but Cat can use it.
2) Why Cat, can not see any properties of Tiger?
Cat can use method "make_a_sound" of Tiger, but can not see its properties... quite strange.
Thanks,
Gennadiy
public class Solution {
public static void main(string[] args) {
Cat cat = new Tiger();
// The result is from Tiger class: A tiger says RRRRR & new tiger property
// Why???
cat.make_a_sound();
// Only cat's and Animal's properties are visible. No Tiger's properties
System.out.println(cat.this_is_a_cat);
}
// Base class
public class Animal {
public String this_is_an_animal = "Animal";
public void make_a_sound() {
System.out.Printf("I'm an animal");
}
}
// Extends base class
public class Cat extends Animal {
public String this_is_a_Cat = "Hi, I'm a cat";
public void make_a_sound() {
System.out.Printf("A cat says meey");
}
}
// Extends prev. class
public class Tiger extends Cat {
public String this_is_a_Tiger = "Tiger";
public void make_a_sound() {
System.out.Println("A tiger says RRRRRR");
this_is_a_Tiger = "new tiger property";
System.out.println(new_tiger_property);
}
}
}
You defined cat as type Cat. That means cat can do anything that any other Cat can do. The Animal object does define the make_a_sound function so it's available to all Animal instances. When you run your code, the variable cat points to a Tiger instance so when make_a_sound is called, it's the one in Tiger that runs. That's the whole point of inheritance.
For your second question, cat is of type Cat so you can only do things with it that you can do with any Cat object. Since this_is_a_Tiger is not something every Cat object has, it is not available to cat even though cat really points to a Tiger.
But you could do this:
if (cat instanceof Tiger) {
Tiger tiger = (Tiger)cat;
System.out.println(tiger.this_is_a_Tiger);
}
Why Cat uses Tigers method? See below example of "make_a_sound" method. It's from Tiger, but Cat can use it.
Answer) Because when you say Cat cat = new Tiger() you are not saying any cat,you are saying you want sound of the Tiger and not any generic cat.Tiger is using cat's "make_a_sound" method by over riding the implementation by the Tigers sound.
if you had not overriden tigers "make_a_sound" method then the Cat's "make_a_sound" method will be called.You can try it out by saying super().make_a_sound in Tiger class or removing implementation of this method.
2) Why Cat, can not see any properties of Tiger? Cat can use method "make_a_sound" of Tiger, but can not see its properties... quite strange.
Answer) If parents classes would know everything about child class then OOPS will be broken.In OOPS each class should only know about what it does and nothing else.It does not care of other class responsibility.
This link could give you some concept regarding Overriding in Java:
https://www.geeksforgeeks.org/overriding-in-java/
For simplicity, Overriding only take effective on methods (regarding Question 1), but not on field variables (regarding Question 2).
Related
I have the following code:
public class Animal {
public <T extends Animal> void doSomething(T instance) {
//do stuff
}
}
but the parameter to the method should be of the same type as the class it's being called on. E.g. this is valid:
public class Dog extends Animal {}
public class Cat extends Animal {}
Dog dog1 = new Dog();
Dog anotherDog = new Dog();
dog1.doSomething(anotherDog);
But this is NOT valid:
dog1.doSomething(new Cat());
Is there any way to achieve this without implementing the method on all the subclasses? Do don't want to do that because there are a lot of subclasses and it would be too repetitive.
Generics serve to link things together. They tell the compiler that relationships exist between 2 different places that types occur. However, in your signature, T occurs only once: As parameter. This is useless. Why not just write void doSomething(Animal instance)? Your code is just a more complicated, and less flexible way of writing that. After all, any animal, even an instance of a subclass of animal, is an animal. There is nothing you can pass to the method <T extends Animal> void doSomething(T animal) that you cannot pass to void doSomething(Animal animal)!
What you want is both not possible and non-sensical. Imagine it was possible to tell java that the parameter of doSomething must be of the same type as the receiver of doSomething, then, consider this code:
Dog dog = new Dog();
Cat cat = new Cat();
Animal dogA = dog; // dogA and dog are pointing at the exact same object!
Animal catA = cat; // dogA and dog are pointing at the exact same object!
dogA.doSomething(catA); // so this would compile and run, then.
Look at that last line. No amount of type-based insistence that 'the parameter must be of the same type as the receiver' you care to add to java can ever make the compiler refuse to compile this code. And yet there is no difference between that and dog.doSomething(cat), because dog and dogA as well as cat and catA are referring to the same object.
And yet, that is evidently what you want. Thus, what you want is not a sensible thing to want.
There are things you can do, but this almost always leads to more problems. You have to generify your own type:
public class Animal<S extends Animal<S>> {
public void doToSibling(S other) {}
}
But this requires you to declare: class Dog extends Animal<Dog>, and there is nothing actually stopping you from class Dog extends Animal<Cat>. The S is not so much 'self type' as 'the thing I can do doToSibling to'.
I don't think there is an implicit way to reference to an overriding class.
You can declare the reqired subtype as generic argument on animal itself to have the described effect.
public class Animal<T extends Animal<?>> {
public void doSomething(final T instance) {
//do stuff
}
}
public class Dog extends Animal<Dog> {}
public class Cat extends Animal<Cat> {}
That beeing said, in practice it is hard to imagine where you want to go from here. What could a method contain that only two dogs can do but two different animals can't but also can be implemented with the same code?
This is often the point where you want to overthink if a common abstract base-class really is helpful in the long run. If the implementation code turns out to be different for all the animals, maybe a common interface on independent classes might be the better option.
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.
In the book, they are trying to create their own arrayList Class using an array object, using polymorphism.
I understand what the code is doing but it will not allow it to compile because their is no dog or cat class.
I have each of them in seperate files.
error: animal cannot be resolved to a type
public class MyAnimalList {
private Animal[] animals = new Animal[5];
private int nextIndex = 0;
public void add(Animal a ) {
if (nextIndex < animals.length) {
animals[nextIndex] = a;
System.out.println("Animal added at " + nextIndex);
nextIndex++;
}
}
}
//next snippet
public class AnimalTestDrive{
public static void main (String[]args) {
MyAnimalList list = new MyAnimalList():
Dog a = new Dog();
Cat c = new Cat();
list.add(a);
list.add(c);
}
}
Okay so the whole concept of Polymorphism is Objects can be categorized into more generic objects.
For example: Dogs are Animals, Cats are Animals, and Animals are Living Things
So Polymorphism allows you to define a bunch of generic characteristics(i.e. fields and methods) for one class(Animal) so that all other classes that are categorized under that class(Cats, Dogs, ect) can extend those characteristics.
Now the reason your code is not working is because you have not defined the class Dog or Cat in order to do that you need to first create a class animal that has certain attributes as such:
public class Animal{
//some fields
//constructor
//methods
}
and then create two other classes Dog and Cat that extend that (extend is a key word meaning that this object is in the category of)
so you would then create:
public class Dog extends Animal{
//some fields
//constructor
//methods
}
public class Cat extends Animal{
//some fields
//constructor
//methods
}
Do you a modern IDE (e.g. eclipse) ? or are you doing it from command line ?
** If you are NOT using an IDE, I strongly suggest you to do so at the beginning. It will help you go smoother and faster pace. **
If you are using command line tools to write your programs, take a close look at oracle documentation
Specially -cp parameter
You have to provide a folder where java can find compiled class files, that's what -cp is used for. For your case, java seems not to be able to find other .class files (Animal, or Dog etc).
Polymorphism Concept
Dog, Fish and a Bird are all animals. So they all inherit some basic concepts. For example all of them move. However a dog runs, a fish swims and a bird flies. Let me show you how it is done in OO:
abstract class Animal{
move();
}
class Dog extends Animal{
private run(){
...
// implementation
...
}
public move(){
run();
}
}
class Bird extends Animal{
private fly(){
...
implementation
}
public move(){
fly();
}
}
class Fish extends Animal{
private swim(){
...
implementation
}
public move(){
swim();
}
}
I hope it makes sense =]
PS: Above code is pseudo code, Not Java
1) an public animal class must be created
2) both a dog and a cat sub-class must be created, both must extend animal. Extending from animal will allow both dog and cat to accept the "add" method.
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
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.