I have read in multiple places that final methods are early bound but none offers a satisfactory reason. I doubt how can it be so coz even in a final method called on parent class reference, compiler cannot say whether parent's non final or child's final method is called.
Please advice.
class Parent {
void meth() {
System.out.println("parent");
}
}
class Child extends Parent {
#Override
final void meth() {
// TODO Auto-generated method stub
System.out.println("child");
}
public static void main(String[] args) {
Parent parent = new Parent();
Parent child = new Child();
child.meth();
parent.meth();
}
}
In the above code method meth() called on child(a Parent reference) is a final method but then the JVM should need to use a method look up table at run time as in its the child or parent method being called.
Naturally, early binding can occur only if the reference's static type is a class where the method has the final specifier.
Binding in java happens in two stages. At compile time the type of the reference as known to the compiler is used to bind the method to the highest method up the type hierarchy it can be. E.g. if calling toString() on a Number type variable, then the compiler knows it has to call Number.toString() or a sub-class override rather than Object.toString().
Secondly when invoking the method at runtime, the runtime type of the object is looked at and the most specific method in the type hierarchy is found and invoked. I.e. in the case of Number.toString above, if the object is an Integer it will find Integer.toString and call that.
If the method is final in the type of the reference / variable then this second step can be skipped because we know there can be no sub-class override. This is what Dima Rudnick means by the static type. So again with my example, if Number.toString was final, and the variable was type Number then we don't need to look at the runtime type to know what method we're invoking.
Note: for the purposes of this I'm assuming Object, Number and Integer all have a specific toString method rather than relying on the inherited one.
Related
We have a Parent and child class, which has method with the same name but argument are as primitive and wrapper. Could someone please explain the reason whether this would be referred as Method Overriding and Method overloading. Running this program would invoke Parent method - which would be overriding and not overloading, looking for explanations.
class Parent {
public void takeValue(int a) {
System.out.println("take value method from parent is invoked");
}
}
class Child extends Parent {
public void takeValue(Integer a) {
System.out.println("take value method from child is invoked");
}
public static void main(String[] args) {
Parent p = new Child();
p.takeValue(new Integer(51));
}
}
The method is overloaded.
Running this program would invoke Parent method - which would be overriding and not overloading
Yes. You're calling takeValue on a Parent variable, which means that the compiler will look for a signature match on the Parent class. The overload is not even visible here (signatures are matched based on static types, i.e., java finds the method based on the declared data type of the variable on which the method is called, not with the data type of the object assigned to the variable, which would be a runtime thing).
And because public void takeValue(Integer a) is not considered by the compiler when checking the method invocation, p.takeValue(new Integer(51)); is linked to Parent.takeValue(int) by virtue of autoboxing (it would have matched the other method if both of them were visible - or declared in the Parent class in this example).
This is overloading. You have same name but type of input parameters are different.
To confirm that, you will get an error when you try to attach the #Override annotation.
Integer and int are different types.
So I was playing around in Java to understand the concept of polymorphism, and I wrote this:
public class Practice
{
public static void main(String[] args)
{
Parent p = new Child();
p.instanceMethod();
}
}
class Child extends Parent {
public void instanceMethod(){
System.out.println("child's instance method");
staticMethod();
}
public static void staticMethod() {
System.out.println("child's static method");
}
}
class Parent {
public void instanceMethod(){
System.out.println("parent's instance method");
staticMethod();
}
public static void staticMethod() {
System.out.println("parent's static method");
}
}
So the output of this is:
child's instance method
child's static method
Why is the the static method called upon from the child's class and not from it's static type, Parent's class?
Is it because, it is first called by the instance method in child's class, so at that point its type is already fully dynamic, aka child's type?
static methods don't 'do' polymorphism. At all.
non-static (i.e. instance) methods do. The signature of the method is bound entirely statically; the actual prospect of finding which method to actually run in the type hierarchy is done entirely dynamically (late binding).
For static methods, the entire thing is entirely static.
So, let's go through this code:
p.instanceMethod()
The expression p is of type Parent. The compiler looks at the signatures available in Parent and all its supertypes and determines that the full method signature that this invocation of instanceMethod() is attempting to invoke is void instanceMethod(). This call (Parent::instanceMethod()V in bytecode speak) is encoded in the emitted .class file.
At runtime, the system checks the actual runtime type of what the p expression resolves to (which is the new Child() you did earlier), and does dynamic dispatch. The public void instanceMethod() of Child, which clearly overrides the one from Parent, is selected and executed, therefore, "child's instance method" is printed.
staticMethod() in Child
Next, let's look at that staticMethod invoke: at compile time, javac determines that this is clearly a reference to the staticMethod() that's right there, in Child. It encodes, in the bytecode an INVOKESTATIC bytecode to Child::staticMethod()V. Dynamic dispatch is not now or ever applied to static method calls.
At runtime.. that method is called.
Simple as that.
Perhaps you expected that a static method still first checks the call context but that's not how java works.
I have a question about method binding. As you know, binding of private, static and final methods happen at compile-time, while binding of overridden methods happen at runtime.
In the following, we have a method something() in Parent, which is not overridden in the corresponding subclass Child.
class Parent {
void something() {
}
}
class Child extends Parent {
}
public class Main {
public static void main(String[] args) {
Parent p = new Child();
p.something(); // still dynamically bound?
}
}
Is the call of p.something() in our main program (although it is not overridden) still dynamically bound?
First of all, the method signature is determined at time of compilation. However, method binding is always done at runtime. The exact rules for the runtime dispatch are defined in JLS ยง15.12.2.5.
So as you are probably guessing now, the call of p.something(); is still dinamically bounded.
As a sidenote, check out this to clearly understand polymorphism.
Let's have this method in parent class:
public void calculateSum(int a, final int b) { }
And the child class has:
public void calculateSum(int a, int b){ }
So is it method overloading or method overriding?
It's overriding, as the number and type of parameters are the same.
Overloading is when the type or number of parameters changes.
The final on the method parameter just instructs the compiler that the variable value (or reference) shouldn't be changed inside the method... this also affects the runtime, as final variables are published safely.
The child class method is overriding the parent class method. The child class method doesn't define a new set of arguments. The 'final' modifier doesn't affect argument type, just if it can be assigned a new value.
If method signature(which include method name and parameter list) is same along with return type(Assignment Compatible) then it's called overriding. Adding modifier to the parameter does not change the parameter type. So your answer is overriding.
Given the following code:
SuperClass :
package poc.poc;
public class SuperClass {
private void method() {
System.out.println("SuperClass!");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SuperClass s = new SubClass();
s.method();
}
}
SubClass :
package poc.poc;
public class SubClass extends SuperClass {
public void method() {
System.out.println("Subclass!");
}
}
When I run the main method of SuperClass , I would expect to get an exception of some sort, but actually the code in the SuperClass is run, rather than the code in the SubClass, and therefore running an instance method of the superclass type on a subclass instance.
Why does this happen?
EDIT: Doesn't this violate encapsulation?
P.S. When changing to protected rather than private modifier, polymorphism starts to kick in and we're back to something I would call "expected behavior"
There is no way to override a private method. Instead, the subclass is hiding it. That means that when the subclass is used polymorphically, the method is not considered one of the parent's existing methods. It's like a whole new method that's not available through polymorphism.
The private method is not part of the parent's class contract. Polymorphism only applies to methods that are part of the parent's contract. If it wasn't like that, you could cause a class to act differently than its contract, by changing implementation where the author wanted it to be private. If the author wanted you to do that, they would have used protected instead. In effect, a private method is like final.
In this particular main method, because it is defined in the actual parent's class, it is able to see a private method and therefore able to call it. If your main method has been in any other class and tried to call it, it would have failed.
A private method cannot be overrided, that alone explains what you see here. You are able to call the method in your main because the main is in the same class, otherwise it would not be possible.
You correctly analyzed what happens when changing private to protected : the method is now overridable and the "nearest" definition of it is executed when calling it on a subclass instance.