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.
Related
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 am learning late binding and static binding. Now I am confused about these code.
Here is my analysis:
hello() is non-static method, so we should use the dynamic binding, that is Child.
But there is no hello() method in child class, so go to its super class. Find hello() and print the first line "Hello from parent call calssMethod".
Since the classMethod() is static, so we should use static binding of c, that is also Child. So the output is "classMethod in Child".
So the out put should be
Hello from parent call calssMethod
classMethod in Child
class Parent{
public static void classMethod() {
System.out.println("classMethod in Parent");
}
public void instanceMethod() {
System.out.println("InstanceMethod in Parent");
}
public void hello() {
System.out.println("Hello from parent call calssMethod");
classMethod();
}
}
class Child extends Parent{
public static void classMethod() {
System.out.println("classMethod in Child");
}
public void instanceMethod() {
System.out.println("InstanceMethod in Child");
}
}
public class AA {
public static void main(String[] args) {
Child c = new Child();
c.hello();
}
}
Now, here is the problem. The IDE shows that the output is:
Hello from parent call calssMethod
classMethod in Parent
What's the right analysis process?
What if I make hello() method static?
Class (static) methods aren't overridden as instance methods. When you call the method 'hello()', it will use the method of the parent. When you refer to the class method there, you're referring to the method defined in the class 'Parent'.
Besides that, you should declare your Child instance as 'Parent c = new Child()'. Because you aren't adding new methods to your subclass but rather changing the implementation, you don't lose access to the methods of the subclass. If you were to have to method that returns a Parent object but you return a Child object declared as you did, you'd get problems.
EDIT: To add to this, usually there are 2 reasons to use inheritance: specialisation and extension.
For specialisation, you use define your methods in your superclass and your subclasses differ in how they implement those methods. For example a superclass Animal with subclasses Cat and Dog. 'Animal' has a method makeSound(). You can imagine that both subclasses are going to have a different implementation.
For extension, you use a superclass as a base class containing everything that overlaps. Other than that, the subclasses might have very different implementations and uses. A lot of interfaces have this kind of use.
Whenever we call child class's object, firstly it always find parent class and execute it. As you have static classMethod in both classes so it always run parent's classMethod not child's. You can achieve required answer only by overriding it.
If you make hello() method static even then it will give you same output.
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.
So I know that in Java when you have a static method you are supposed to call it with the format ClassName.method() rather than use the same structure as you would for instance methods, namely:
ClassName myObject = new ClassName();
myObject.method();
However, if you were to do it this way it would still be valid code and would work. Let's say I decide to do this where the method in question is static, and have the following setup:
public SuperClass {
public static int foo(int x) {
return x;
}
}
public SubClass extends SuperClass {
public static int foo(int x) { // Overriding foo() in SuperClass
return x + 1;
}
}
public MyDriver {
public static void main(String[] args) {
SuperClass myObject = new SubClass(); // Upcasting.
System.out.println(myObject.foo(5)); // This should polymorphically print 6
}
}
What prints out on the screen, however, is 5 rather than 6. Why?
Static methods apply only to the class they are defined in, and they cannot be overridden.
When you call myObject.foo(5), you are calling SuperClass.foo(5) in reality, because you declared myObject as a SuperClass, regardless of whether you instantiated it as one.
The proper way to call a static method is to call it directly from the class it is declared in, so if you wanted to call SubClass.foo(), you must call it from an explicitly declared SubClass instance (meaning no upcasting), or you need to call SubClass.foo() like so.
The simple answer is that calling static methods from instances evaluates to calling those same methods from the declared type with no instance rather than the instance type.
I am not certain of this, but I would not be surprised if when the code is compiled into byte-code, that the instance static method call would actually be compiled into a direct call to the declared type.
Edit: An upvote brought my attention back to this and I cleaned up the explanation to make it more clear and fix some negligible grammatical mistakes on my part. I hope this helps future readers.
Using instances of a class to call that class's static methods is something you should avoid, since it can cause confusion. If you need to call any method polymorphically, make it an instance method. You cannot polymorphically call a static method. The reason the SuperClass invocation is called is because that is the apparent class of myObject at compile-time. This effect can also be seen in the following scenario:
public void doSomething(SuperClass param) {
System.out.println("SuperClass");
}
public void doSomething(SubClass param) {
System.out.println("SubClass");
}
public void test() {
SuperClass myObject = new SubClass();
doSomething(myObject);
}
If test() is called, SuperClass will be printed.
Static methods don't depends on the instance, they belong to the class and only to the class, in fact if you have a static method you'll always access to one unique instance always.
myObject.foo(5)
is only a shortcut, what you really are doing is
SuperClass.foo(5)
Static methods are treated as global by the JVM, they are not bound to an object instance at all. By the way, you can only overload static methods, but you can not override. So check for "Oracle Documentation for Overriding and Hiding Documents".
Defining a Method with the Same Signature as a Superclass's Method:
-----------------------------------------Superclass Instance MethodSuperclass Static Method
Subclass Instance Method Overrides Generates a compile-time error
Subclass Static Method Generates a compile-time error Hides
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.