I have the following code. Two questions follows:
class Parent {
private void test()
{
System.out.print("test executed!");
}
static void print(){
System.out.println("my class is parent");
}
}
class Child extends Parent
{
static void print(){
System.out.println("my class is Child");
}
}
public class Inheritence {
public static void main(String[] args)
{
Child p1 = new Child();
Parent p = new Child();
System.out.println("The class name of p is "+p.getClass());
System.out.println("The class name of p1 is "+p1.getClass());
System.out.println("p instance of child "+ (p instanceof Child));
System.out.println("p1 instance of child "+ (p1 instanceof Child));
//p.test();
p.print();
}
}
The output is:
The class name of p is class Child
The class name of p1 is class Child
p instance of child true
p1 instance of child true
my class is parent
I thought the classname for p
will be Parent
, since it is of type Parent
. However, it prints as Child
. so how would I get the type
of p
.
Second question here is whether private methods are inherited or not. while many articles including this, comments that private methods are not inherited, I see in the below example it is inherited. It could be some type casting issues below.
class Child1 extends Parent1
{
}
public class Parent1 {
private void test()
{
System.out.print("test executed!");
}
public static void main(String[] args)
{
Parent1 p = new Child1();
p.test();
Child1 c = new Child1();
//c.test(); The method test from parent1 is not visible
}
}
Output is : test executed!
here I am calling test
method on Child1
object which is of type Parent1
. Child1
has no test
method since it is not inherited. but I still get the output, which indicates the private methods are inherited! If test
was a protected method, and I override in child class, it is the overridden method that gets executed though the type of object on which it is called is parent(parent p1 = new child1());
EDIT: After few comments, I made class Parent1 and class Child1 seperate and a new Class called App that constructs a parent and child object. now I cannot call p.test
in the code below.
class Child1 extends Parent1
{
}
class Parent1 {
private void test()
{
System.out.print("test executed!");
} }
public class App1{
public static void main(String[] args)
{
Parent1 p = new Child1();
p.test();//The method test from parent is not visible
Child1 c = new Child1();
//c.test(); //The method test from parent1 is not visible
}
}
To address the second question: it may be helpful to keep the concepts of "inheritance" and "visibility" distinct. A private
method m
is only visible inside the class C
where the method is declared. So you can't use m
at all from outside C
. Furthermore, even inside C
, you can't use x.m()
unless the object x
is declared to be of type C
. But objects of a subclass still have the method m
, and that method can be called, but only inside C
. This example will compile (even if the two classes are in separate files):
public class Class1 {
private void test () { System.out.println ("test"); }
public void doThis (Class2 c) {
// c.test(); -- does not compile [1]
((Class1)c).test();
}
}
public class Class2 extends Class1 {
public void doSomething () {
doThis (this);
// ((Class1)this).test(); -- does not compile [2]
}
}
Note that inside doThis
, you can still call the test
method of c
, even though c
has type Class2
. However, you can do this only because the code is inside the class Class1
that declares the test()
method (which is why [2] doesn't compile); and you can do it only by casting c
to an object of type Class1
(which is why [1] doesn't compile). However, even after you cast it so that the compiler sees it as an expression of type Class1
, the actual object still has type Class2
. And if you were to call an overridden method polymorphic
like this: ((Class1)c).polymorphic()
, it would call the method defined in Class2
, not Class1
, since the object is still actually a Class2
object.
So I think that in some sense, test
is inherited even though it's private; it just isn't visible in Class2
.
MORE: I think it's also helpful to understand that there's a difference between a compile-time type and a run-time type (or instance type). If you declare a variable Parent x;
then x
's compile-time type is Parent
. If you have a function f
whose return type is Parent
, then an expression like obj.f(arg,arg2)
will have type Parent
. But at run-time, if a variable or expression has compile-time type Parent
, the actual type at run-time can be Parent
or any of its subclasses. The run-time type will be based on how the object was constructed. So a variable can have a compile-time type Parent
and a run-time type Child
. Then you just need to know which type is used and when. For checking whether a method is visible (which is where private
comes into play), the compile-time type is used. For deciding which method to call when a child subclass overrides a method, the run-time type is used (that's what polymorphism is). For .getClass()
, the run-time type is used. Anyway, that's how I think about things so that I don't get too confused.
EXAMPLE: Let's say we have:
class Parent { }
class Child extends Parent { }
class Grandchild extens Child { }
In some other class, we have
Parent x1 = new Parent();
Parent x2 = new Child();
Parent x3 = new Grandchild();
The variables x1
, x2
, and x3
all have a compile-time type of
Parent
. This means all three variables could refer to an instance
of Parent
, or an instance of Child
or Grandchild
or any other
subclass of Parent
. And that's what happens above: x2
will refer
to an instance of Child
, and x3
will refer to an instance of
Grandchild
.
Similarly:
private Parent getAParent(int n) {
if (n == 0) return new Parent();
if (n == 1) return new Child();
if (n == 2) return new Grandchild();
throw new IllegalArgumentException();
}
Parent x4 = getAParent (0);
Parent x5 = getAParent (1);
Parent x6 = getAParent (2);
x5
refers to an instance of Child
, and x6
refers to an instance
of Grandchild
.
But the compile-time type of all the variables and the getAParent
calls is still Parent
. The compiler does not know what class the
variable or function call actually refers to when you run the program.
So if you declare a method play()
inside Grandchild
, these are
still illegal:
x3.play (); // ERROR
x6.play (); // ERROR
getAParent(2).play (); // ERROR
because the compiler thinks of the two variables and getAParent(2)
as having type Parent
, not Grandchild
. And play
isn't defined
for Parent
. To see if those variables have a run-time type that
has a play
method would require the compiler to generate code to
check at run-time, and the compiler doesn't do that.
That's why p.test()
works in your second example. Even though p
refers to an instance of Child1
, p
's compile-time type is
Parent1
since you declared it as having type Parent1
. And the
compiler sees that Parent1
has a test
method; and since the code
is inside Parent1
, the test
method is visible even though it's
private. That's why it works. The compiler doesn't generate code to
check what run-time type p
actually refers to. Hope this helps
explain things.