What really happens on inheritance in Java? - java

Suppose I have two classes Parent and Child, and Child inherits from Parent. I have three methods in Parent, out of which two are public and one is private.
Normally we say that all the non-private methods are inherited into the Child class, but I'm confused about exactly what happens. Does Java make a copy of the methods in the Child class, or does it use some kind of reference to maintain the relationship?
class Parent{
// Private method
private void method1(){
System.out.println("In private method of Parent class");
}
void method2(){
// calling private method
method1();
}
void method3(){
// calling private method
method1();
}
}
class Child extends Parent{
}
class MainClass{
public static void main(String[] args){
Child child = new Child();
// calling non-private method which internally calls the private method
child.method2();
}
}

Does Java makes copy of the methods in the Child class or it uses some kind of reference to maintain the relationship?
Latter. Take a look at invokespecial. Java recursively looks up methods one class at a time. The first matching method is called. This is why calling a virtual (default) method is slower than calling a final method.
In general, the actual code within a method is not copied when you inherit from a class containing that method.

Neither.
Inheritance is a programming language concept, not a real action. When you investigate the compiled Child class, e.g. with javap, you won’t find any artifact related to the three methods of Parent. There will be the information that Child has the superclass Parent, but no mentioning of the inherited methods, neither as references nor as copies.
The fact that Child conceptionally inherits methods from Parent comes into play when you actually try to invoke one of them through a variable whose compile-time type is Child, like in your Test class. Then it is up to the compiler to find the inherited methods in order to compile the code containing the invocation correctly. It is also up to the compiler whether it searches the class hierarchy every time it resolves a target method of an invocation or whether it collects the existing methods in certain data structures to speed up subsequent lookups and which data structures it uses.
This process is more complicated than you might think. There may be multiple candidates among which the compiler has to select one and it may even fail due to ambiguity. The result of the process will be a decision about whether the invocation is valid and, in case it is valid, a single target method and its actual signature.
The compiled invocation will contain the name and signature of the target method and a reference to the compile time type of the reference on which it is invoked, i.e. Child. It will not contain the information that the actual method has been inherited from Parent. This is intentional. Whether Child declares the method itself, inherits it from Parent or overrides a method of Parent should not affect the code of the invoker Test nor the compatibility between compiled class files.
This implies that at runtime a class like Test may contain a reference, given by name and signature, to a method in Child not being stored in the class file of Child, in other words, the JVM is responsible as well, for making the concept of inheritance working. At the same time, it has to ensure that the concept of overriding works, when a method invocation is executed.
The way it implements this is also unspecified, leaving room for different strategies. Searching class hierarchies on every invocation would be legal, but lead to poor performance.
A common technique is a vtable. Associated with every class is a table (array) containing references to the available methods, be it declared or inherited. On initialization of a subclass, its table will start with a copy of the superclass’ table, having entries for new methods appended at the end and entries of overridden methods changed. At some time, the method invocation will be linked by finding the index of the vtable entry, appropriate to the specified name and signature. A typical strategy is to do the lookup on the first invocation. The instruction is then modified to refer to the index to avoid subsequent lookups. From then, subsequent executions consist of fetching the vtable for an object’s runtime class and getting the method reference from the table’s entry.
Considering that, you could say that at runtime, inheritance is typically implemented as some kind of reference—but wait.
Implementations like Oracle’s JVM are capable of doing hotspot optimizations in which the context of often executed code is considered. There might be, for example an inherited method which itself invokes methods which have been overridden in some subclasses. When the JVM finds out that this method is called very often on a single concrete subclass, it may create an optimized version for that particular case. Then, a copy of the method’s code will be the starting point for the subsequent code transformations, inlining code of the specific subclass, etc.
Since such sophisticated implementations will use references for non-optimized code while using optimized copies in other cases, an alternative to the initial answer answer could be:
Both.

Method bodies aren't copied in the undefined method body of a subclass. Instead, when you call
Child child1 = new Child();
child1.method1();
It will look through its hierarchy, going up a level every time it can't find an implementation. First it will check Child which has no implementation. One level above that there's Parent which does, so it will use that one.As correctly mentioned by #Dante above that this is achieved via the super() call in the constructor of the Child Class. This image might help you get a better picture :
I think your confusion is somehow associated to the point
of non inheritance of the private methods.So,I would like to address that as well
Why Private Members are not inherited ?
You could say that private members are not inherited, because nowhere can Child refer explicitly to value. I.e. any code like this.value can't be used within Child, nor can obj.value be used from some calling code (obviously).
However, in another sense, you could say that value is inherited. If you consider that every instance of Child is also an instance of Parent, then that object must contain 'value' as defined in Parent. Even if the Child class knows nothing about it, a private member name value still exists within each and every instance of Child. So in this sense, you could say that value is "inherited" in Child.So without using the word "inheritance", just remember that child classes don't know about private member defined within parent classes. But also remember that those private members still exists within instances of the child class.
Note: The the JLS states (http://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#8.2):
Members of a class that are declared private are not inherited by
subclasses of that class. Only members of a class that are declared
protected or public are inherited by subclasses declared in a package
other than the one in which the class is declared.

Java does not make a copy of the methods.The methods that are inherited stay with the parent class only.
Now you must me wondering,How does child class get access to them?
The answer lies in understanding the super keyword.
The super keyword is used to refer to object of immediate parent class.The very first thing super does is initialize object of parent class.This means it is responsible for creating object of parent class and is used to refer to that object.
The super(); is implicitly the first statement inside constructor of child class,however you can do that explicitly also.
Now the important part:
If you have the following:
super();
not as your first statement inside child class constructor,then compile error is generated saying:
call to super must be first statement in constructor.
The reason is:
Because the child class is assumed to have the inherited methods,but do not possess a copy of them.
The inherited methods are basically with parent class,so it is important to create object of parent class first,so that whenever following is used
instance_of_child.method_of_parent();
The method will be actually invoked from object of parent class,which was already created by super(explicitly or implicitly used).
This is the reason why you can have child class constructor like:
Child()
{
super();
parent_method();
}
but not like:
Child()
{
parent_method();
super();
}
because parent_method(),that is the inherited method requires reference to object of parent class which is provided by super().

Related

how can super refer to parent class object when we create a child class object?

When we create a child object, single object is created of child class which uses parent class variables. this is my understanding. I have read on many places that super refer to parent class object but here only one single object is created which inherits its members from parent class.
Does a parent class object is implicitly created inside child one to which super refers to?.I dont exactly get how people have written and in which context that it refer to parent class object ? when only child class object is created singly.
Have a look there for super meaning and use.
https://docs.oracle.com/javase/tutorial/java/IandI/super.html
Basically, you can see any object as an onion with the inner peel being Object and the outer one your object's class, with all the super classes in between. Each peel comes with its own attributes, class (overloaded, overridden, or new) and constructors (same) but the whole thing is a single object, each peel only seeing toward the inner core (except for overriden methods that are called to their outmost overriding peel - i.e. a method implementation that does not exist yet at the the considered peel declaration : see https://pretagteam.com/question/calling-an-overridden-method-superclass-an-calls-overridden-method)
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super.
You can also use super to refer to a hidden field (although hiding fields is discouraged).
You can also use super(...) to invoke a specific superclass constructor (whether it is not public or need to be called with specific parameters)

How does the parent class's defined method get called in a sub-class object?

This is a bit more of an implementation-related question, or I could be overthinking it. Let's say I have a subclass that inherits from the parent class. From my understanding, it will inherit the method definitions from the parent class but not the constructor. We need to provide or the compiler will provide constructor through the super method call. The reason we do this is that the method definitions we obtain from the parent class in the sub class will not exist without a parent class object instance.
Does this mean, when I call a parent class object defined method that is not overridden yet in the subclass, will be internally called inside the subclass on a parent object instance? I was thinking that would be the case since the sub-class does call the parent class constructor and make an instance of it.
I think you have been mislead by the term "constructor". If the wording had been "initializer", IMHO that would have been clearer - but the established term is "constructor".
If your subclass Sub extends a parent class Parent, then creating a Sub instance will not create a second, separate Parent instance.
When your Sub constructor calls the super() constructor, this just means that the aspects described in the Parent class get initialized the way that Parent constructor wants it, e.g. filling the fields defined in Parent with appropriate values. This super() constructor call does not construct/create a new instance, but initializes the Parent-defined part of the one and only instance, and that's why I think the name "constructor" misleading.
After that super() call, your Sub constructor is free to do its turn. All this happens on a single instance that combines fields (and methods) from both classes.
So, when you call a Parent-defined method on a Sub instance, there is no distinct Parent instance that might receive the call, it all happens on the single Sub instance. As the method is defined inside Parent, it does not know anything about the Sub extensions to Parent, and e.g. can't access fields defined in Sub (unless using "dirty tricks" like reflection).
If you like, you can think of a Sub instance as being a Parent instance where some fields and methods have been added to the end. Parent-defined methods work on the Parent part of the instance(1), and Sub methods see the complete instance.
The reason we do this is that the method definitions we obtain from
the parent class in the sub class will not exist without a parent
class object instance.
So, this is not true. The "parent class object instance" does not exist (at least not in the sense of an instance distinct from the subclass one), it is the first part of the subclass instance, which is then followed by the subclass fields.
(1) There are a few caveats, e.g. if a Parent method is overridden in the Sub class, but IMHO that goes beyond the scope of this question.

Why doesn't java allow to assign weaker access privileges to static methods in a child class?

I understand why java doesn't allow to set weaker access privileges for overridden methods, but why is it the same for static methods? I mean, these methods only hide each others, right? So what's the problem from the encapsulation point of view?
P.S.
I know that there are 5 rules for hiding a method
The method in the child class must have the same signature as the method in the parent
class.
The method in the child class must be at least as accessible or more accessible than the
method in the parent class.
The method in the child class may not throw a checked exception that is new or
broader than the class of any exception thrown in the parent class method.
If the method returns a value, it must be the same or a subclass of the method in the
parent class, known as co-variant return types.
The method defined in the child class must be marked as static if it is marked as
static in the parent class (method hiding). Likewise, the method must not be marked
as static in the child class if it is not marked as static in the parent class (method
overriding).
But after all, I don't get the idea from the encapsulation prospective
The same rules are valid and for method hiding
https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.3
Static methods have special access permissions that allow friend access to members within a instance. For example, you could have a static method called create that creates a default instance of the class and directly modifies data within the instance without using instance properties or instance methods (just for a usage example, not necessarily a usage recommendation).
Because of this special access, lower access permissions to the static methods could allow you to create an object in a state that you could not otherwise use, or modify an object in an unpredictable and non-encapsulated way.
This is only a minor annoyance for most user-defined classes, but allowing this when sub-classing e.g. containers could expose serious undefined behavior problems.

When instantiating a Java object, is an object of the parent class created automatically?

Suppose I create an object, and one constructor of the parent class is run. With this constructor a new object of the parent is created as well behind the scenes?
If not, where are the private fields of the parent class stored? You can actually call any method of the parent object (with or without super) which operates of the private fields invisible of the calling object.
If anyone who is most familiar with the Java Memory Model, his or her answer is very welcome!
With this constructor a new object of the parent is created as well behind the scenes?
No, only one instance is created. The created instance contains the attributes of the current class and all of its superclasses.
If not, where are the private fields of the parent class stored?
Like all class attributes they are stored on the heap. There is no difference in terms of memory location if they are defined in the current class or the superclass.
It doesn't create two objects, only subclass object.
When inheriting from another class, you must call super() in your constructor. If you don't, the compiler will insert that call for you as you can plainly see.
The superclass constructors are called because otherwise the object would be left in an uninitialized state.
Remember inheritance is an "is a" relationship between the base class and the subclass, thus every time you have an instance of a subclass, by definition you will also have an instance of the base class (as part of the instance, not as two separate instances). To initialize the base class properly the constructor is called.

Virtual Functions during Construction. Why Java is different than C++

I had a test today and one of the questions was about using a virtual method in C++ constructor. I failed this question, I answered that there shouldn't be any problem, however after reading this I found out I was wrong.
So I understand that the reason for not allowing that is because the derived object is not fully initialized and therefore calling it's virtual method can cause invalid consequences.
My question how was it solved in Java/C# ? I know that I can call derived method in my base constructor, I would assume that these languages have exactly the same problem.
Java has a very different object model from C++. In Java, you cannot have variables which are objects of class type -- instead, you can only ever have references to objects (of class type). Therefore, all members of a class (which are only references) start out trivially as null until the entire derived object has been set up in memory. Only then do the constructors run. Thus by the time a base constructor calls a virtual function, even if that function is overridden, the overridden function can at least correctly refer to members of the derived class. (Those members may not themselves be assigned yet, but at least they exist.)
(If it helps, you can also consider that every class without final members in Java is technically default-constructible, at least in principle: Unlike in C++, Java has no such things as constants or references (which must be initialized in C++), and in fact there are no initializer lists at all. Variables in Java simply don't need to be initialized. They're either primitives which start as 0, or class type references which start as null. One exception comes from non-static final class members, which cannot be rebound and must actually be "initialized" by having precisely one assignment statement somewhere in every constructor [thanks to #josefx for pointing this out!].)
understand that the reason for not allowing that is because the derived object is not fully initialized and therefore calling it's virtual method can cause invalid consequences
Wrong. C++ will call the base class's implementation of the method, not the derived class's. There are no 'invalid consequences'. The only valid reason for avoiding the construct is that the behavior sometimes comes as a surprise.
This is different from Java because Java calls the derived class's implementation.
In C++ every polymorphic class( class that has at least one virtual function ) has a hidden pointer at start of it( usually named v-table or something like that ) that will be initialized to the virtual table( an array of functions that point to the body of each virtual function ) of that class and when you call a virtual function C++ simply call ((v-table*)class)[index of your function]( function-parameters ), so if you call a virtual function in base class constructor v-table point to virtual table of the base class since your class is base and it still need some initialization to become child and as a result you will call implementation of the function from base not from child and if this is a pure virtual function you will get an access violation.
but in java this is not something like this, in java whole the class is something like std::map<std::string, JValue> in this case JValue is some variant type( for example a union or boost::variant ) when you call a function in constructor of base it will find function name in the map and call it, it is still not the value from the child but you can still call it and if you changed it in the prototype, since prototype created before your constructor you can successfully call function from child but if function required some initialization from constructor of the child you still get error or an invalid result.
so in general it is not a good practice to call a function from child( for example a virtual function ) in base class. if your class need to do this add an initialize method and call it from constructor of your child class.
Every Java constructor looks like this:
class Foo extends Bar {
Foo() {
super(); // creates Bar
// do things
}
}
So if you place code working on derived methods in do things, seems to be logic, that this base object was initialized properly, after calling its constructor in super();
I think that Java/C# avoid this problem by constructing from derived class backwards rather than in C++ from base class forwards.
Java implicitly calls super() in a classes constructor so by the time the first line of written code in a derived class constructor is called all the constructors of all inherited classes are guaranteed to have been called and so the new instance will have been completely initialised.
I think also in C++ a new instance of a class begins life as the base class and gets "upgraded" to the final class type as we move down the inheritance chain. This means that when you call a virtual function in the constructor you'll actually be calling the version of that function for the base class.
In Java and presumably C# a new instance starts life as the required class type so the correct version of the virtual method will be called.
Java does not entirely avoid the problem.
An overridden method called from a superclass constructor that depends on fields of the subclass will be called before those fields have been initialized.
If you're in control of the entire class hierarchy, you can of course just make sure your overrides don't depend on subclass fields. But it's safer to just not call virtual methods from constructors.

Categories

Resources