I have three classes.
Class A
public class A {
}
Class B
public class B extends A {
public void hello(){
System.out.println("hello");
}
}
Class C
public class C extends B {
}
Class Test
public class Test {
public static void main(String[] args) {
A a = new C();
a.hello(); // The method hello() is undefined for type A
}
}
The code above will not compile because it reports an error that reads "The method hello() is undefined for type A"
My question is, since "a" is a C object, why doesn't a.hello() use the hello() method in the parent class of B?
If I add a hello method to A class, only then does the code above use the hello() from B class, but why do I have to add hello() to A class in order to use the method from B class?
A is a top level class in your hierarchy. It sees only those methods that are defined within it. Methods defined by its subclasses are not accessible to A. Sure, you can assign C to variable A, and then you can use it wherever A can be used, but now C will be limited to methods that A has.
It makes sense when you think about it. When you define a type (A), you expect it to behave according to your definition (which does not include anything about C fields and methods). You do not expect it to suddenly have everything that subclasses might have defined (e.g., imagine situation where a hundred people extended your class in various ways - top class would become incredibly bloated and broad).
That is why subclasses extend parent classes - they add additional functionality that is not (and probably should not be) defined in its parent. However, the parent itself has no awareness of the additional functionality and cannot use it. Each class can only use what it has defined or its parent(s) has defined. Hence, when you assign C to the parent's type, you will only get those methods that A is aware of (but with C's implementation).
Consider:
public class Animal {
public void walk() {
System.out.println("Walking");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Woof");
}
#Override
public void walk() {
System.out.println("Doggy walk");
}
public static void main(String[] args) {
Dog dog = new Dog();
Animal animal = new Animal();
Animal animalDog = new Dog();
dog.walk(); // "Doggy walk"
dog.bark(); // "Woof"
animal.walk(); // "Walking"
animal.bark(); // Error: bark() is not defined in the Animal class
animalDog.walk(); // "Doggy walk"
animalDog.bark(); // Error: Animal class has no bark()
}
}
Since we assigned Dog to Animal type, it can only use methods that are defined in Animal class. But note that the behavior will be the one that you defined in Dog class for the same method.
If you must use the method and for some reason you have not assigned it to a type that has the method, you should cast it accordingly, e.g.:
((Dog) animalDog).bark(); // "Woof"
I think you're a bit confused on how polymorphism works. You're saying "a" is a "c" object, which is a misleading assumption that many beginners make. So here's an example to illustrate what's happening:
Say you have an "Animal" class, which is extended by a separate "Dog" class, because a Dog is an Animal. So we can write:
Animal someAnimal = new Dog();
The above statement can be rewritten as:
Dog someDog = new Dog();
Animal someAnimal = someDog;
which shows that a Dog object can be stored as an Animal object. Why? Because a Dog is an Animal. You can't do
Dog someDog = new Animal();
because an Animal is not [necessarily] a Dog.
This points back to your original assertion. Your "a" is not a "c" object because you never wrote something like:
C a = new A(); // sidenote : this will give you error, as you are saying the analogous Animal is a Dog
As a result, your superclass (which is "A") can not access methods from the subclass (which in this case is "B") because superclasses don't inherit from subclasses (it's the other way round).
It's all about variable types. You are instantiating C class, but treat result object as A. Interface of A class does not contain 'hello' method, that's why you can't use it in your example.
To solve the problem you should either add your method to A or update type of the variable to B.
When you declare a variable as having the type of the superclass, you can only access (public) methods and member variables of the superclass through that variable.
In your question A is a parent class of B ,B is the parent class of C
(i.e. A->B->C) and you create the object of C class through A . So, according to your program firstly it try to find the hello() method in A class because it is a super parent class of C, which is not defined hello() method that's why it shows an error.
When you define a as an A type object (A a = new C();), it only has access to the members and methods of type A. To do what you want, either define hello() on type A or define a as an object of type B (B a = new C();). This is because the compiler is keeping track of which methods it has available. If, for some reason, you don't actually have access to the instantiation but you need to access something from B but it's handed to you as an A object, then you can cast it:
if (a instanceof B) (B a).hello();
else throw new Exception();
In method overriding you should have same method in super class.In this scenario most super class is A
Related
Why would you declare the "thing" object as the super-class when you can use the subclass, which would give you access to all of the same methods and fields and wouldn't require type casting for methods in the B class.
public class A{}
public class B extends A{}
public class main()
{
A thing = new B();
}
This is called Polymorphism. If you had another class called C extends A you could create a List<A> and put both B and C there. Then you could iterate over them and call the common method etc.
Maybe because you want to feed() several Animals at same time, without caring about the real type of Animal:
interface Animal { void feed();}
class Dog implements Animal { public void feed() { /* feed a dog (give it a cat) */ }}
class Cat implements Animal { public void feed() { /* feed a cat (give it a bird) */ }}
class Cow implements Animal { public void feed() { /* feed a cow (give it some grass) */ }}
// Now I have some animals mixed somewhere (note that I am allowed to have the array declaring a supertype (Animal), and it can contain many kind of different animals)
Animal[] manyAnimals = new Animal[]{ new Dog(), new Cat(), new Cow() };
// I can feed them all without knowing really what kind of Animal they are. I just know they are all Animal, and they will all provide a feed() method.
for(Animal some : manyAnimals) { some.feed(); }
It is polymorphism.
This example might help you understand it.
In a company there are both Permanent and Contract employees are there. The salary calculations happen differently for different type of employee. But PF calculation is common for both type of employees. So in this case you can write common code in super class(Employee) and only custom code in sub class(PermanentEmployee and ContractEmployee). This way you can make code reusable instead of writing again and again and also you can achieve dynamic polymorphism. Most of the time the type of employee is decided at run time.
I'm currently studying polymorphism but I don't understand the following statements:
"The type of a class variable determines which method names can be used with the variable.
However, the object named by the variable determines which definition with the same method name is used."
I'm confused.
It means that the methods you can call from an object are limited by the type of that object. For example, let's say you have these classes:
public class Animal {
public void sayName() {
System.out.println('animal');
}
}
public class Cow extends Animal {
#Override
public void sayName() {
System.out.println('cow');
}
public void sayMoo() {
System.out.println('mooo');
}
}
Now, you can declare your cows like this:
Animal cow = new Cow();
You can do that because Cow is a subclass of Animal. However, if you do that you'll be unable to say moo with your Cow, because you have created the variable as a simple Animal. Therefore, the method sayMoo is unaccessible from your variable.
The type of a class variable determines which method names can be used with the variable.
This means that if you have a class Base and a variable of type Base:
Base base = ...
You can call a method
base.method()
only if method() is defined in class Base (or a super-class of Base).
However, the object named by the variable determines which definition with the same method name is used.
This means calling base.method() doesn't always execute method() of class Base.
If, for example, Derived is a class that extends class Base and overrides method() method, then if the actual type of the instance referenced by base is Derived:
Base base = new Derived();
then calling
base.method();
will execute Derived's class implementation of method().
The "type of a class variable" means the static (compile-time) type of a reference variable.
The "object named by the variable" means the dynamic (run-time) type of the instance (object) referenced by the variable.
Consider the following code (and explanations inside):
class A {
public void methodA() {
System.out.println("A -> A");
}
public void methodB() {
System.out.println("A -> B");
}
}
class B extends A {
#Override
public void methodB() {
System.out.println("B -> B");
}
public void methodC() {
System.out.println("B -> C");
}
}
A a = new B();
// here, the type of variable a determines which methods can be called on that var.
// A declares two methods, methodA and methodB and only those can be called.
// Even a is actually referring to an instance of B which declares methodC
// as well, the call a.methodC() is not valid because a has type A.
a.methodA(); // prints A -> A
// Here, the actual implementation (the object that a refers to) determines
// which implementation is being called and because the actual object
// is an instance of B, we get B -> B printed.
a.methodB(); // prints B -> B
// a.methodC(); cannot be called
To put it simple, you will be able to execute methods specific to your class variable and not of the class instance.
In this way you are able to use interfaces as declared class variable and instantiate a new object.
Display display = new TV();
You will be able to execute whatever method Display has, but not the specific method that TV has.
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 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.
But, if the superclass has an abstract method, and that method is implemented in it's subclass, which is concrete, we will still be able to call the subclass' implementation of the method using an Object of the superclass.
How come?
Same for overloaded methods, the subclass' implementation is called even though you call it using a reference of the superclass.
Let me be more specific here...
Suppose Animal is a superclass and Dog is a subclass.
Now, I do:
Animal a = new Dog();
What this means is that a is a reference to an animal class, right?
Now, if I do, a.function(); (assume that the function is defined in Animal and overridden in Dog), the Animal's version ought to be called as a is a reference to an animal, but it's the other way around.
It means that a super class cannot call methods that are defined in sub classes because the super class doesn't know them. For abstract methods, the super class is aware of them so it can call them. This also happens with non-abstract and non-final methods: they can be modified by the sub class without noticing the super class, and the super class may still work with no problems.
What you're describing is the difference between compile time and execution time (also called run time). At compile time, a variable can only call methods defined on the type the variable is declared e.g. Animal animal then animal variable can only call methods that are defined in Animal class. At execution time, the execution of the method will be handled by the class that belongs to the instance of the object reference e.g. Animal animal = new Dog(); then animal behavior will be defined by the behavior stated in Dog class.
Example:
public class Animal {
abstract void breath();
}
public class Dog extends Animal {
#Override
public void breath() {
System.out.println("Dog breathing");
}
public void bark() {
System.out.println("woof!");
}
}
public class Client {
public static void main(String[] args) {
//animal variable is of type Animal
//and initialized as a Dog object reference
Animal animal = new Dog();
//dog variable is of type Dog (also an Animal)
//and initialized as a Dog object reference
Dog dog = new Dog();
animal.breath();
dog.breath();
//line below throws a compiler exception
//since animal is declared as type Animal
//not all Animals know how to bark
animal.bark();
//line below compiles fine
//since dog is declared as type Dog
//and Dog's know how to bark
dog.bark();
}
}