I am asking a quite simple question, but I am bit confused in this.
Suppose I have a class Parent
:
public class Parent {
int name;
}
And have another class Child.java
:
public class Child extends Parent{
int salary;
}
And finally my Main.java class
public class Main {
public static void main(String[] args)
{
Parent parent = new Child();
parent.name= "abcd";
}
}
If I make a child object like
Child child = new Child():
Then child
object can access both name and salary
variables.
My question is:
Parent parent = new Child();
gives the access of only name
variable of Parent class.
So what is the exact use of this line??
Parent parent = new Child();
And also when it is using dynamic polymorphism then why the variable of child class is not accessible after doing this
Parent parent = new Child();
Let's say you'd like to have an array of instances of Parent class, and a set of child classes Child1, Child2, Child3 extending Parent. There're situations when you're only interested with the parent class implementation, which is more general, and do not care about more specific stuff introduced by child classes.
It's simple.
In this case the type of the object is
Parent
. AntParent
has only one properties. It'sname
.And in this case the type of the object is
Child
. AntChild
has two properties. They'rename
andsalary
.The fact is that there's no need to initialize non-final field immediately at the declaration. Usually this’s done at run-time because often you cannot know exactly what exactly implementation will you need. For example imagine that you have a class hierarchy with class
Transport
at the head. And three subclasses:Car
,Helicopter
andBoat
. And there's another classTour
which has fieldTransport
. That is:As long as an user hasn't booked a trip and hasn't chosen a particular type of transport you can't initialize this field. It's first.
Second, assume that all of these classes must have a method
go()
but with a different implementation. You can define a basic implementation by default in the superclassTransport
and own unique implementations in each subclass. With this initializationTransport tran; tran = new Car();
you can call the methodtran.go()
and get result without worrying about specific implementation. It’ll call overrided method from particular subclass.Moreover you can use instance of subclass everywhere where instance of superclass is used. For example you want provide opportunity to rent your transport. If you don't use polymorphism, you have to write a lot of methods for each case:
rentCar(Car car)
,rentBoat(Boat boat)
and so forth. At the same time polymorphism allows you to create one universal methodrent(Transport transport)
. You can pass in it object of any subclass ofTransport
. In addition, if over time your logic will increase up and you'll need to create another class in the hierarchy? When using polymorphism you don't need to change anything. Just extend classTransport
and pass your new class into the method:and
rent(new Airplane())
. Andnew Airplane().go()
in second case.When you compile your program the reference variable of the base class gets memory and compiler checks all the methods in that class. So it checks all the base class methods but not the child class methods. Now at runtime when the object is created, only checked methods can run. In case a method is overridden in the child class that function runs. Child class other functions aren't run because the compiler hasn't recognized them at the compile time.
This situation happens when you have several implementations. Let me explain. Supppose you have several sorting algorithm and you want to choose at runtime the one to implement, or you want to give to someone else the capability to add his implementation. To solve this problem you usually create an abstract class (Parent) and have different implementation (Child). If you write:
you bind your implementation to Child class and you can't change it anymore. Otherwise if you use:
as long as Child extends Parent you can change it in the future without modifying the code.
The same thing can be done using interfaces: Parent isn't anymore a class but a java Interface.
In general you can use this approch in DAO pattern where you want to have several DB dependent implementations. You can give a look at FactoryPatter or AbstractFactory Pattern. Hope this can help you.
First, a clarification of terminology: we are assigning a
Child
object to a variable of typeParent
.Parent
is a reference to an object that happens to be a subtype ofParent
, aChild
.It is only useful in a more complicated example. Imagine you add
getEmployeeDetails
to the class Parent:We could override that method in
Child
to provide more details:Now you can write one line of code that gets whatever details are available, whether the object is a
Parent
orChild
:The following code:
Will result in the output:
We used a
Child
as aParent
. It had specialized behavior unique to theChild
class, but when we calledgetEmployeeDetails()
we could ignore the difference and focus on howParent
andChild
are similar. This is called subtype polymorphism.Your updated question asks why
Child.salary
is not accessible when theChild
object is stored in aParent
reference. The answer is the intersection of "polymorphism" and "static typing". Because Java is statically typed at compile time you get certain guarantees from the compiler but you are forced to follow rules in exchange or the code won't compile. Here, the relevant guarantee is that every instance of a subtype (e.g.Child
) can be used as an instance of its supertype (e.g.Parent
). For instance, you are guaranteed that when you accessemployee.getEmployeeDetails
oremployee.name
the method or field is defined on any non-null object that could be assigned to a variableemployee
of typeParent
. To make this guarantee, the compiler considers only that static type (basically, the type of the variable reference,Parent
) when deciding what you can access. So you cannot access any members that are defined on the runtime type of the object,Child
.When you truly want to use a
Child
as aParent
this is an easy restriction to live with and your code will be usable forParent
and all its subtypes. When that is not acceptable, make the type of the referenceChild
.If you assign parent type to a subclass it means that you agree with to use the common features of the parent class.
It gives you the freedom to abstract from different subclass implementations. As a result limits you with the parent features.
However, this type of assignment is called upcasting.
The opposite is downcasting.
So, if you create instance of
Child
and downcast it toParent
you can use that type attributename
. If you create instance ofParent
you can do the same as with previous case but you can't usesalary
because there's not such attribute in theParent
. Return to the previous case that can usesalary
but only if downcasting toChild
.There's more detail explanation