public class Parent {
public void printParent()
{
System.out.println("I am the Parent");
System.out.println("----this is ::---" + this);
this.printChild();
}
private void printChild()
{
System.out.println("This is my child");
}
}
public class Child extends Parent {
private void printChild()
{
System.out.println("I am the child");
}
}
public class RelationshipTester {
#Test
public void testRelation()
{
Child parent = new Child();
parent.printParent();
}
}
This is the output :-
I am the Parent
----this is ::---datastructures.lists.inheritance.Child#1a692dec
This is my child
The object is of the type Child , yet it doesn't call the child method and the parent one. I have given this.printChild();
In the Parent class, you have declared printChild as private ... and called it. A private method cannot be overridden. Your printChild in the Child class is not known to the Parent class.
If you were to change the private modifier to public, then you would have an override, and your example should output what you are expecting.
Why won't Java let you override a private method? Well, basically, if you could do it then there would be no way to write a class with an abstraction boundary that a child class could not break. That would (IMO) be a major language design short-coming.
Why doesn't Java report an error or warning? Well there is no error because this is legal Java according to the JLS. As for a warning ... if you compile Parent in isolation there is no problem, because the code as written is declaring and using a private method. If you compile Child in isolation, the compiler can't see the private method in the Parent class. (Indeed, it may not even exist in the version of the .class file for Parent that you are compiling against.) Only if you compiled Parent and Child at the same time might the compiler spot something a bit odd.
The keyword 'this' point to the current class instance and here is the private void printChild(). And then you have created an object of class Child at RelationshipTester class. The scope of the two function is private which means to is bounded to that class only. Thus, it won't overwrite the subclass and would execute the Base class's method.
private methods are not inherited. When you call printParent, you're calling a method on Parent and when that method refers to this, it's referring to an instance of that class (Parent), which has its own printChild method. Making Parent#printChild a protected method should give the expected result.
public class Child extends Parent {
protected void printChild(){
System.out.println("I am the child");
}
}
use protected, not private
In this program we have to remember 2 points:
If we create an object for a subclass (here child) then memory also created for the super class. That means if the method that we are calling that is not found in the child class then Java Virtual Machine goes to parent class and checks for the method that we are calling and if the method is found it will execute. If the method is found in child class itself it will not go to the parent class.
private, static and final methods can't be overridden.
Since the scope of the method is private it is not visible to other class.
Related
What is happening in the code below? Please explain the output:
class Parent{
private void fun(){
System.out.println("parent fun\n");
}
public void accessFun(){
System.out.println(this);
this.fun();
}
}
class Child extends Parent{
private void fun(){
System.out.println("child fun");
}
}
class Test{
public static void main(String[] args) {
Child a = new Child();
Parent b = new Parent();
Parent c = new Child();
a.accessFun();
b.accessFun();
c.accessFun();
}
}
Output:
Child#7960847b
parent fun
Parent#3b192d32
parent fun
Child#16f65612
parent fun
Why the line this.fun() is not giving compile-time error?
I think fun is a private member in Child class and therefore can't be accessed from outside the Child class(from public member of it's Parent class).
Why Parent class version of fun() is being called by this.fun()? Note this refers to child class object.
Private members are not inherited.
I think this might be the key point that you are missing here. What this means is that Child.fun does not override Parent.fun. They are just two plain old methods that has nothing to do with each other.
When you call accessFun, control always goes into this bit of code in Parent:
public void accessFun(){
System.out.println(this);
this.fun(); <---- here
}
Now, since we are now inside Parent, we can access fun. And since Parent.fun is not overridden, it calls Parent.fun and not Child.fun.
I think fun is a private member in child class and therefore can't be accessed from outside the class(may even from public member of it's Parent class).
That is a complete misunderstanding. if private members can't be accessed from outside of the class, not even through public methods, then they will be much less useful. Why even have them in the first place?
"Private members can only be accessed by members declared in the same class" is probably a better thing to remember.
private fun() in Parent is called by public accessFun() of same Parent class. And public accessFun() is called in main() of Test class.
Here accessFun() is public so it can be called from any where.
For example just like Pojo classes private members are accessed through public setters and getters
The fun method in parent is private and the child fun() method is not overriding the parent fun() method. But the accessFun method is public so it can be called from the child class and is publicly accessible.
So when you call accessFun() method it will be calling the parent class fun() method. Not the child class fun() method as it is private. That is why you wont get an error.
I think fun is a private member in child class and therefore can't be accessed from outside the class(may even from public member of it's Parent class).
Sometimes everything comes from "outside". The main call comes from outside for example.
If a private member can not be accessed from outside, it would always be dead code and this makes no sense.
The difference is the understanding from direct-access and indirect-access.
In all cases you call the method non-directly via the method accessFun().
In dynamic method binding a superclass reference can only call a subclass method which is inherited and overrode by it. However, the otherwise can be implemented.
abstract class in
{
abstract void print();
}
class a extends in
{
String name=this.getClass().getSimpleName();
void show()
{
System.out.println("class "+name);
}
void print()
{
show();
}
}
class Main
{
public static void main(String args[])
{
in x;
x = new a();
x.print();
}
}
Here, it prints successfully
class a
Also getClass() returns the subclass name instead of superclass name as this refers to the superclass object in main method.
A parent object reference is just constrained by the methods that it has in its class definition. If those methods are overridden by subclass, and at run time, if the actual object referred by the parent reference is of subclass type, then that overridden method is invoked. It doesn't matter if the overridden method invokes methods that are not originally present in the parent class or accesses the variables that are not present in the parent class.
This is what polymorphism is all about. It is by design meant to be this way as it makes program extension easier in case if we have different specific inheritance hierarchies where the parent class need not know the exact implementation of certain methods and can make things implemented by the subclasses as some sort of contract.
Future is unknown A developer writing a class A.java today can never predict in future the names or signatures of the methods which any other developer may include in his class extending A.java. Also such classes may be numerous with each having separate methods.
Base class should never be coupled with its sub classes. It must not care about how the sub classes are implemented.
Although it is not recommended but still if you wish to invoke the method defined in one of the sub class you may do it by typecasting like below.
public class Parent {
public class someMethod(){
if( this instanceof Child1){
((Child1)this).someAdditionalMethod();
}
}
}
public class Child1 extends Parent{
public class someAdditionalMethod(){
}
}
Is it common practice to always use super for calling methods out of the superclass, even when I'm NOT overriding the method?
Assume
public class Parent{
public void method() {
}
}
So
public class Child extends Parent {
public void someMethod() {
super.method();
}
}
or
public class Child extends Parent {
public void someMethod() {
method();
}
}
Thanks for your input.
Calling super tells the JVM to explicitly look to the parent class' version of a method. Continuing with your example, if you just call
method()
The JVM will first search in the calling class for the method (in this case Child) before looking at the parent class. On the other hand, if you call
super.method()
then the JVM will explicitly look at the parent class for an implementation, even if Child has an method called method().
Putting these two ideas together, you should probably always use super when you intend to call the parent class' method. If your class does not override the method, then you could call without super. But even this becomes problematical if someone were to refactor your class later on and override the method.
The leading question is easy to answer:
Is it common practice to always use super for calling methods out of the superclass, even when I'm NOT overriding the method?
No, its not common practice. On the contrary, its dangerously confusing to do so. You call methods normally, because the main point of inheritance is to allow the classes to override methods to change/extend their behavior. You normally don't care about at which level a method is actually implemented.
The obvious exception is when you do override the method yourself and you want/need the parents functionality.
Now to the dangerously confusing part of explicitly calling super:
public class CallSuper {
static class Parent {
public void foo() {
System.out.println("Parent.foo");
}
/**
* Calls foo to do the main work
*/
public void bar() {
System.out.print
foo();
}
}
static class Child extends Parent {
public void foo() {
System.out.println("Child.foo");
}
public void bar() {
super.foo();
}
}
static class GrandChild extends Child {
public void foo() {
System.out.println("GrandChild.foo");
}
}
public static void main(String[] args) {
Parent p = new Parent();
Parent c = new Child();
Parent g = new GrandChild();
System.out.print("Parent.foo() = ");
p.foo();
System.out.print("Child.foo() = ");
c.foo();
System.out.print("GrandChild.foo() = ");
g.foo();
System.out.print("Parent.bar() = ");
p.bar();
System.out.print("Child.bar() = ");
c.bar();
System.out.print("GrandChild.bar() = ");
g.bar();
}
}
If you run this example it will output (added line numbers for clarity):
1 Parent.foo() = Parent.foo
2 Child.foo() = Child.foo
3 GrandChild.foo() = GrandChild.foo
4 Parent.bar() = Parent.foo
5 Child.bar() = Parent.foo
6 GrandChild.bar() = Parent.foo
The first four lines are not surprising, we get what foo implements at each level, respectively Parents's bar calling its foo. It starts to get odd at line 5. Child bypasses its own override of foo by calling super.bar(), so while its foo() is specialized, bar() is not. In Line 6, you see that GrandChild inherits this oddity from Child, so the somewhat innocent looking super.foo() in Child's bar has now broken GrandChild's expectations that its override of foo() is effective for all bar() as well.
Now if you imagine foo() and bar() actually doing something useful and that they have a meaningful relationship with each other, e.g. you are led to believe (either by Parent's documentation or just common sense) that overriding foo() will change the behavior of bar(), too. Child's "super" is breaking that.
As a rule of thumb, if you see a "super.x()" call anywhere outside of an actual override of "x()", its probably an accident lurking to happen.
Is it common practice to always use super for calling methods out of the superclass? Or is it redundant code?
It's not redundant. It have a special purpose of invoking parent class method (though you ovveriden). When you don't want, don't invoke. If you current class is not child of that class, super won't work for you.
Also if you call an overridden supermethod, does it use the supermethod or the lowest method?(in the inheritance tree)
The overridden method. Since you overridden it in your class.
If you're not overriding, let's talk about performance.
If you call an inherited method in your class, let's say, methodInSuperclass(), the JVM will look for that method first in your class, then up the class hierarchy until it finds it.
Using super.methodInSuperclass() tells the JVM to go directly to the superclass to look for that method.
So, using the super keyword improves performance by a few mills. It's ugly code, but it's not redundant as it will bring some performance improvement.
Consider using it if time is critical.
Calling the super method or not depends entirely on what you are trying to do. If you want to do what the parent class did plus some additional action, then calling the super method is good. If you're doing something completely different in the child implementation then do not call the super method. When you do call the super method in a hierarchy of classes, it calls the one closest to your child class in the hierarchy.
In some cases you may have an API where calling the super method is part of the overall contract. The clone method is such a case.
If Child is having the same version method with Parent, JVM will call the Child's version instead of Parent's version if without "super". The "super" keyword is helpful if you want to make sure the Child is always calling the Parent's version method.
It was my understanding that a child cast to the parent type (as in Super sc = new Child();) would call the parent class's static methods, and access the parent class's non-hidden fields, but would make use of the child class's instance methods.
This does not seem to hold true for the case of private instance methods (those in which overriding does not actually take place because the parent method is private.)
I understand that the fact that there is no overriding (private parent methods are not visible to the child, so they can only be hidden.) would mean that the child wouldn't look up the heirarchy to see the parent's version of the method when the instance method is invoked from the child.
However, the exact opposite of what I'd expect (the version present in the child being called) is occurring. The parent version of the private method is invoked.
Why does this happen if the instance methods of the child are typically invoked, and within the child, there is a method with an identical signature (a perfect match for the invocation of method2() in this case) already present, hiding the same method in the parent class?
package whatever;
public class A {
public void method1(){
System.out.println("A method1().");
}
//using "final" here to emphasize that this is a hiding, not an override.
private final void method2(){
System.out.println("A private method2().");
}
public static void main(String[] args)
{
A a = new A().new B();
a.method1(); //calls B method 1
((A.B)a).method1(); //calls B method 1
a.method2(); //calls A private method 2 **I expected it to call B private method 2
((A.B)a).method2(); //calls B private method 2
}
public class B extends A {
public void method1(){
System.out.println("B method1().");
}
private final void method2(){
System.out.println("B private method2().");
}
}
}
First, B is actually a nested class and, oddly enough, the private members of nested classes can by accessed by the outer class. Otherwise, it wouldn't even be legal to do ((A.B)a).method2(); (The reverse is also true. B can access private members in A as well.)
That said, to answer your actual question, the reason a.method2(); calls the private method in A is that private methods are not virtual, as they cannot be overriden at all. (How could they be, if inheriting classes aren't supposed to even know about them?) As such, they are bound at compile time, which means using the declared type of the variable. A a is declared as A, but (A.B)a is cast at compile time to B. Thus, your first call uses the private method from A and your second call uses the private method from B.
It's quirky that the facts in those two paragraphs don't interact with each other. It might reasonable to expect that, since the nested class "knows" about the outer class's private members, an override might be possible. But it's not. Private functions never show up in the vTable and can never be overridden.
Short answer: because your B class is in the same file (.java) with the one that contains #main() method.
The reason that the private method of the parent class is visible to the child class is that the child class is an inner class of its parent class in your case.
Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private
In the following code, the constructor of Child has reduced visibility from public to private, which is allowed. The inherited methods, such as test(), cannot have reduced visibility. Why does Java operate this way?
class Parent {
public Parent(){}
public void test()
{
System.out.print("parent test executed!");
}
}
class Child extends Parent{
private Child(){}
private void test(){
System.out.print("child test executed!");
}
}
Constructors are not inherited, so Child() doesn't override Parent().
As for the methods, if you have (if Child() were public)
Parent p = new Child();
p.test();
Had it been allowed, this would be invoking a private method. So narrowing the access while overriding is not permitted.
When extending a class you are stating that your class is an extension of the parent class ("IS-A" relationship). What this means is that your class will have all methods of your parent class. This is the same as implementing an interface in java except you gain the method definitions (and fields) from your parent and not just methods declared in the interface. In interfaces constructors are not present because they are not methods. Constructors are special as they belong entirely to the class they are declared on. They declare how to construct only themselves.
In order to construct an object you must know that objects class.
class A {
private message;
private A() {
message = "You created an A";
}
public A(String message) {
this.message = message;
}
public void printMessage() {
System.out.println(message);
}
public static A createAnA() {
return new A();
}
}
class B extends A {
public B() {
super("You created a B");
}
}
A anA = new B(); // This will work
A anotherA = new A(); // This is not allowed as the constructor is private
A yetAnotherA = A.createAnA(); // This works too
So when we constructed B we can say that it is an A. Even though the constructor A is private this is due the constructor not being a part of the interface. The only thing we are saying about B when we assign it to a field of type A is that it has the methods of declared in A. In this case printMessage and createAnA.
That is why you can make the constructor private without changing the definition of the class. Now, why are you not allowed to make the method private when overriding a parents signature. This comes to having varying definitions of the [class].method(). Let's say that you could make your method private. Let's say that you declared a printMssage in the B class. Your reasoning is that you want that method for your use only inside the method and you want your parents printMessage to be used when called externally. Now, you wrote a method like this in the B class.
public void adjustMessage(String additional) {
message = getMessage() + additional();
}
Which version of get message would be executed? Your private one or the public one of your parents? The Java dispatcher would of course choose the public one as it is the one declared in the interface. So we we look at this example we can see if you did make your method have different a lower privilege your method could never be dispatched too which would just make things confusing for the reader.
This is a very good question.