Misunderstanding Dynamic Binding - java

From what I understand about dynamic binding, the JVM, at runtime, looks at the actual type of an object and searches for an implementation in that class and works its way up through the inheritance levels.
For example if we have: Vehicle v = new Car();
Assuming that the class Car extends Vehicle, we can see that the reference variable type is Vehicle and the object type is Car.
If we were to say: v.start():
The JVM would look for the start method implementation first in the Car class and then in the Vehicle class.
An example of this is in this code:
public class scratch{
public static void main(String [] args){
Vehicle v = new Car();
v.start();
}
}
class Vehicle{
public void start(){
System.out.println("Vehicle class");
}
}
class Car extends Vehicle{
public void start(){
System.out.println("Car class");
}
}
The output of this code, as expected is: "Car class"
This is my question: If I take out the start method from class Vehicle, completely erase it, the program won't run anymore. From what I understand about dynamic binding, the JVM should still look at the actual type of the object (which in this case is Car) and still run the car implementation of the start method. However, it does not do this.
Why?

The problem with removing start() from Vehicle has to do with polymorphism. In Vehicle, if you define start() here, then that is what says that all Vehicles, even subclasses, have that method.
If you remove start() from Vehicle(), then it can't be guaranteed that any Vehicle has a start() method, even though we know it's a Car that does have start(). What if there is a HorselessCarriage class that extends Vehicle but doesn't define start()? Then, there is no start() method. For that reason, if there's no start() method on Vehicle, you can't call start() on a Vehicle variable.
The whole point of being able to call start() on a Vehicle is to ensure that any Vehicle implementation has a start() method to call.
UPDATE
The JVM takes the runtime type of the object and looks for a method matching the signature of the method call. If not found, it walks up the inheritance tree to the superclass and looks for the method there.
More details are given in the JLS, Section 15.12.4.4:
Let X be the compile-time type of the target reference of the method
invocation. Then:
If class S contains a declaration for a non-abstract method named m
with the same descriptor (same number of parameters, the same
parameter types, and the same return type) required by the method
invocation as determined at compile time (§15.12.3), then:
If the invocation mode is super or interface, then this is the method
to be invoked, and the procedure terminates.
If the invocation mode is virtual, and the declaration in S overrides
(§8.4.8.1) X.m, then the method declared in S is the method to be
invoked, and the procedure terminates.
If the invocation mode is virtual, and the declaration in S does not
override X.m, and moreover X.m is declared abstract, then an
AbstractMethodError is thrown.
Otherwise, if S has a superclass, this same lookup procedure is
performed recursively using the direct superclass of S in place of S;
the method to be invoked is the result of the recursive invocation of
this lookup procedure.
Here, S appears to be the runtime type of the object.

In nutshell, JVM need one endpoint to begin the search for the reference of the start method, not matter the object type have a method that you want to invoke, JVM need a mirror to ensure you are trying to call an existing method.

When you have the start() method in the Vehicle class, Car is Overriding that method. When you remove the start() method from Vehicle, you are no longer overriding that method. So calling v.start() has no method to call. This is why you should use #Override, so that it is clear in the code what is happening. In order to call start() on Car in the case where there is no start() method in Vehicle, you'd first have to cast the vehicle to the Car class.

But once you remove the method, Vehicle no longer has any "start" functionality: it is an unknown method in the Vehicle class, and you are accessing it through a Vehicle reference. To make java do what you want, you could do
abstract class Vehicle
{
public abstract void start();
}
Your code should then work again, because all children of Vehicle are now guaranteed a start method. But as it stands in your example, once the start method is removed, there's no guarantee that some previous statement hasn't created some other Vehicle descendant, e.g., Motorcycle without a start method and assigned it to your v reference.

I think a simple way to see the problem is to introduce a method. Here's how the method is defined:
public void callStart(Vehicle vehicle) {
vehicle.start();
}
This method lets you pass in a concrete Car or a concrete Vehicle.
Lets pretend that Java lets you compile this code. If Java let you do this for a Vehicle without a start() method, then you'd have to discover the error at runtime. But Java saves you some time by letting you know when you've compile that you have an error.
This is different from some dynamic languages like Javascript. If this were JavaScript you could pass in a concrete Vehicle and then you'd have to discover your error at runtime. Another difference is that in JavaScript, you could pass in a concrete Car and it would work without error. This is called duck typing and is a feature Java doesn't have.

Related

Can dynamic polymorphism allow for greater flexibility than static polymorphism when writing in Java? [duplicate]

Can anyone provide a simple example that explains the difference between Dynamic and Static polymorphism in Java?
Polymorphism
1. Static binding/Compile-Time binding/Early binding/Method overloading.(in same class)
2. Dynamic binding/Run-Time binding/Late binding/Method overriding.(in different classes)
overloading example:
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
overriding example:
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Method overloading would be an example of static polymorphism
whereas overriding would be an example of dynamic polymorphism.
Because, in case of overloading, at compile time the compiler knows which method to link to the call. However, it is determined at runtime for dynamic polymorphism
Dynamic (run time) polymorphism is the polymorphism existed at run-time. Here, Java compiler does not understand which method is called at compilation time. Only JVM decides which method is called at run-time. Method overloading and method overriding using instance methods are the examples for dynamic polymorphism.
For example,
Consider an application that serializes and de-serializes different
types of documents.
We can have ‘Document’ as the base class and different document type
classes deriving from it. E.g. XMLDocument , WordDocument , etc.
Document class will define ‘ Serialize() ’ and ‘ De-serialize() ’
methods as virtual and each derived class will implement these
methods in its own way based on the actual contents of the documents.
When different types of documents need to be
serialized/de-serialized, the document objects will be referred by
the ‘ Document’ class reference (or pointer) and when the ‘
Serialize() ’ or ‘ De-serialize() ’ method are called on it,
appropriate versions of the virtual methods are called.
Static (compile time) polymorphism is the polymorphism exhibited at compile time. Here, Java compiler knows which method is called. Method overloading and method overriding using static methods; method overriding using private or final methods are examples for static polymorphism
For example,
An employee object may have two print() methods one taking no
arguments and one taking a prefix string to be displayed along with
the employee data.
Given these interfaces, when the print() method is called without any
arguments, the compiler, looking at the function arguments knows which function is meant to be called and it generates the object code
accordingly.
For more details please read "What is Polymorphism" (Google it).
Binding refers to the link between method call and method definition.
This picture clearly shows what is binding.
In this picture, “a1.methodOne()” call is binding to corresponding methodOne() definition and “a1.methodTwo()” call is binding to corresponding methodTwo() definition.
For every method call there should be proper method definition. This is a rule in java. If compiler does not see the proper method definition for every method call, it throws error.
Now, come to static binding and dynamic binding in java.
Static Binding In Java :
Static binding is a binding which happens during compilation. It is
also called early binding because binding happens before a program
actually runs
.
Static binding can be demonstrated like in the below picture.
In this picture, ‘a1’ is a reference variable of type Class A pointing to object of class A. ‘a2’ is also reference variable of type class A but pointing to object of Class B.
During compilation, while binding, compiler does not check the type of object to which a particular reference variable is pointing. It just checks the type of reference variable through which a method is called and checks whether there exist a method definition for it in that type.
For example, for “a1.method()” method call in the above picture, compiler checks whether there exist method definition for method() in Class A. Because ‘a1′ is Class A type. Similarly, for “a2.method()” method call, it checks whether there exist method definition for method() in Class A. Because ‘a2′ is also Class A type. It does not check to which object, ‘a1’ and ‘a2’ are pointing. This type of binding is called static binding.
Dynamic Binding In Java :
Dynamic binding is a binding which happens during run time. It is also
called late binding because binding happens when program actually is
running.
During run time actual objects are used for binding. For example, for “a1.method()” call in the above picture, method() of actual object to which ‘a1’ is pointing will be called. For “a2.method()” call, method() of actual object to which ‘a2’ is pointing will be called. This type of binding is called dynamic binding.
The dynamic binding of above example can be demonstrated like below.
Reference static-binding-and-dynamic-binding-in-java
method overloading is an example of compile time/static polymorphism because method binding between method call and method definition happens at compile time and it depends on the reference of the class (reference created at compile time and goes to stack).
method overriding is an example of run time/dynamic polymorphism because method binding between method call and method definition happens at run time and it depends on the object of the class (object created at runtime and goes to the heap).
In simple terms :
Static polymorphism : Same method name is overloaded with different type or number of parameters in same class (different signature). Targeted method call is resolved at compile time.
Dynamic polymorphism: Same method is overridden with same signature in different classes. Type of object on which method is being invoked is not known at compile time but will be decided at run time.
Generally overloading won't be considered as polymorphism.
From java tutorial page :
Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class
Method Overloading is known as Static Polymorphism and also Known as Compile Time Polymorphism or Static Binding because overloaded method calls get resolved at compile time by the compiler on the basis of the argument list and the reference on which we are calling the method.
And Method Overriding is known as Dynamic Polymorphism or simple Polymorphism or Runtime Method Dispatch or Dynamic Binding because overridden method call get resolved at runtime.
In order to understand why this is so let's take an example of Mammal and Human class
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
#Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
I have included output as well as bytecode of in below lines of code
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
And by looking at above code we can see that the bytecodes of humanMammal.speak() , human.speak() and human.speak("Hindi") are totally different because the compiler is able to differentiate between them based on the argument list and class reference. And this is why Method Overloading is known as Static Polymorphism.
But bytecode for anyMammal.speak() and humanMammal.speak() is same because according to compiler both methods are called on Mammal reference but the output for both method calls is different because at runtime JVM knows what object a reference is holding and JVM calls the method on the object and this is why Method Overriding is known as Dynamic Polymorphism.
So from above code and bytecode, it is clear that during compilation phase calling method is considered from the reference type. But at execution time method will be called from the object which the reference is holding.
If you want to know more about this you can read more on How Does JVM Handle Method Overloading and Overriding Internally.
Polymorphism:
Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.
Dynamic Binding/Runtime Polymorphism :
Run time Polymorphism also known as method overriding. In this Mechanism by which a call to an overridden function is resolved at a Run-Time.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
#Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Output:
Inside start method of Car
Static Binding /compile-time polymorphism:
Which method is to be called is decided at compile-time only.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
Output:
Inside Collection sort metho
Static Polymorphism: is where the decision to resolve which method to accomplish, is determined during the compile time. Method Overloading could be an example of this.
Dynamic Polymorphism: is where the decision to choose which method to execute, is set during the run-time. Method Overriding could be an example of this.
Polymorphism refers to the ability of an object to behave differently for the same trigger.
Static polymorphism (Compile-time Polymorphism)
Static Polymorphism decides which method to execute during compile
time.
Method Overloading is an example of static polymorphism, and it is
requred to happens static polymorphism.
Static Polymorphism achieved through static binding.
Static Polymorphism happens in the same class.
Object assignment is not required for static polymorphism.
Inheritance not involved for static polymorphism.
Dynamic Polymorphism (Runtime Polymorphism)
Dynamic Polymorphism decides which method to execute in runtime.
Method Overriding is an example of dynamic polymorphism, and it is
requred to happens dynamic polymorphism.
Dynamic Polymorphism achieved through dynamic binding.
Dynamic Polymorphism happens between different classes.
It is required where a subclass object is assigned to super class
object for dynamic polymorphism.
Inheritance involved for dynamic polymorphism.
Compile time polymorphism(Static Binding/Early Binding): In static polymorphism, if we call a method in our code then which definition of that method is to be called actually is resolved at compile time only.
(or)
At compile time, Java knows which method to invoke by checking the method signatures. So, this is called compile-time polymorphism or static binding.
Dynamic Polymorphism(Late Binding/ Runtime Polymorphism): At run time, Java waits until runtime to determine which object is actually being pointed to by the reference. Method resolution was taken at runtime, due to that we call as run time polymorphism.
Consider the code below:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
Now, looking at the code you can never tell which implementation of methodA() will be executed, Because it depends on what value the user gives during runtime. So, it is only decided during the runtime as to which method will be called. Hence, Runtime polymorphism.
Method overloading is a compile time polymorphism, let's take an example to understand the concept.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
In this example, Person has a eat method which represents that he can either eat Pizza or Noodles. That the method eat is overloaded when we compile this Person.java the compiler resolves the method call " e.eat(noodles) [which is at line 6] with the method definition specified in line 8 that is it method which takes noodles as parameter and the entire process is done by Compiler so it is Compile time Polymorphism.
The process of replacement of the method call with method definition is called as binding, in this case, it is done by the compiler so it is called as early binding.
Following on from Naresh's answer, dynamic polymorphism is only 'dynamic' in Java because of the presence of the virtual machine and its ability to interpret the code at run time rather than the code running natively.
In C++ it must be resolved at compile time if it is being compiled to a native binary using gcc, obviously; however, the runtime jump and thunk in the virtual table is still referred to as a 'lookup' or 'dynamic'. If C inherits B, and you declare B* b = new C(); b->method1();, b will be resolved by the compiler to point to a B object inside C (for a simple class inherits a class situation, the B object inside C and C will start at the same memory address so nothing is required to be done; it will be pointing at the vptr that they both use). If C inherits B and A, the virtual function table of the A object inside C entry for method1 will have a thunk which will offset the pointer to the start of the encapsulating C object and then pass it to the real A::method1() in the text segment which C has overridden. For C* c = new C(); c->method1(), c will be pointing to the outer C object already and the pointer will be passed to C::method1() in the text segment. Refer to: http://www.programmersought.com/article/2572545946/
In java, for B b = new C(); b.method1();, the virtual machine is able to dynamically check the type of the object paired with b and can pass the correct pointer and call the correct method. The extra step of the virtual machine eliminates the need for virtual function tables or the type being resolved at compile time, even when it could be known at compile time. It's just a different way of doing it which makes sense when a virtual machine is involved and code is only compiled to bytecode.

Why can this object access methods of it's parent class?

This question is taken from an AP Computer Science practice test.
public class Bird
{
public void act()
{
System.out.print("fly");
makeNoise();
}
public void makeNoise()
{
System.out.print("chirp");
}
}
public class Dove extends Bird
{
public void act()
{
super.act();
System.out.print("waddle");
}
public void makeNoise()
{
super.makeNoise();
System.out.print("coo");
}
}
Suppose the following declaration appears in a class other than Bird or Dove:
Bird pigeon = new Dove();
What is printed as a result of the call pigeon.act()?
I thought the answer would be "fly chirp", but the textbook says that the answer is "fly chirp coo waddle". I thought that 'pigeon' could only access methods available in Bird? I was under the impression that, if the user wanted to access methods in Dove, 'pigeon' would have to be cast to Dove.
Would Bird pigeon = new Bird(); give the same output? How about Dove pigeon = new Dove();?
Long story short, when you access act method of pigeon, its override from Dove is called.
I thought that 'pigeon' could only access methods available in Bird?
That is certainly true, at least, for situations when no casting is applied. However, method act is available on the class Bird, the statically known type of pigeon, so the call compiles fine.
However, accessing methods is only about being able to call them. What methods do when you call them is decided at runtime based on the dynamic type of pigeon. This is where method overriding comes into play, because Dove overrides Bird's methods, but in addition it also calls Bird's methods. That is why the code hits all four printouts.
Would Bird pigeon = new Bird(); give the same output?
No, the output would be different, because in this case both dynamic and static types of pigeon would be the same, i.e. Bird, so only Bird's implementations would be invoked.
the class Dove does override the methods act and makeNoise of class Bird. Overriding means changing the behavior of a method visible to the sub-class, (in your case Dove). Methods are visible to a sub-class if they have a public or protected access modifier or if they have a package private access modifier and the sub-class belongs to the same package as the super-class does.
pigeon is an instance of Dove.
calling pigeon.act() results in calling Dove.act.
Dove.act calls super.act which is Bird.act.
Bird.act prints fly and calls makeNoise on pigeon resulting in calling Dove.makeNoise.
Dove.makeNoise calls super.makeNoise which is Bird.makeNoise.
Bird.makeNoise print chirp.
Dove.makeNoise prints coo after calling super.makeNoice
What you experience here is polymorphism in action. And instead of answering your various questions directly; I will simply explain the case you are observing.
You call act() on an instance of Dove; that causes a call to super; printing "fly".
That super method then calls makeNoise() ... on "itself". But as said: "itself" is a Dove object; thus you get the Dove noise! "coo"!
Then the Dove implementation ends; and prints "waddle".
The essence is: the exact version of a method that is invoked is determined at runtime and it only depends on the exact type of the object the method is invoked on.
The above gives you all the information you need to answer your other questions yourself. In that sense: don't request answers; ask for explanations; and use those to solve the puzzle yourself!
From your question "I thought that 'pigeon' could only access methods available in Bird? I was under the impression that, if the user wanted to access methods in Dove, 'pigeon' would have to be cast to Dove." This is actually true.
Lets try to find the mssing link in the understanding.
When we have code like Bird pigeon = new Dove(); where Dove extends Bird we have actual object of Dove and reference type is of Bird. As the object is of Dove so it has the methods, both inherited from super class as well as the ones which are added.
Another important point is all the overriden methods have only one instance. Its Overriden meaning the behavior of the same method has been modified, its not an additional separate method. There is only one copy of inherited method not both. Its the overloaded methods which are separate, just the names are same but signature is different. This is the reason you get the behaviour of Dove when you invoke any overriden method.
This one is simple super , using it a sub class can access the accessible (visible) entities (instance properties and methods) of its super class. If a sub class uses super keyword to invoke a method then its the method of the parent class which gets invoked. But again this can be considered that the author of the sub class did it intentionally. Once the class is written and Objects of such class is created then on the object using . (dot operator) users can only invoke whats there in the object. If any method has used super keyword its part of the behavior of the object. Users of the Sub class object can not invoke behavior of the parent class method if its overridden in sub class.
Lastly yes if you wish to invoke any additional method of Dove (Sub class ) using a reference of Bird (Super class) then you need to cast it to Dove.

Why is overriding in JAVA working somewhat differently that from C++?

I have some background in C++ and know some Java too (apparently far from enough).
When I see overriding behavior in Java or C++, it does not seem to differ much. Given below example in JAVA:
class Animal{
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal{
public void move(){
System.out.println("Dogs can walk and run");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();// runs the method in Animal class
b.move();//Runs the method in Dog class
}
}
In Java, you use a base class reference, in C++ you use a base class pointer, and depend on the type of instance it points to (a base class object instance or a subclass instance), you can achieve polymorphism.
The above is based on you call the instance method using a base class reference or pointer, right?
Now I see this example in Java.
What is the order of the Constructors in this Java Code?
Basically it says if a base class function is overriden, then in the process of creating a subclass object, even the base class initialization portion will be affected. See below explanation I copied from above link:
new Son()
=>
Son._init
=> first every constructor calls super()
Father._init
Object._init
who() => is overridden, so prints "son" !!!!!
tell(name) => name is private, so cannot be overridden => "father"
who() => "son"
tell(name) => "son"
Why should this happen? I mean does this conform to how polymorphism should be use? When making base class portion of initialization, why use overrided function from subclass?
In Java doc http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5, I only find this:
"Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized. "
But I don't know the reason behind it, and it feels strange.
Any thoughts?
This is one of the extremely rare cases where C++ is trying to protect you from shooting yourself in the foot more than Java does. (Or at least it has the noble intention to do so.)
You are very likely to shoot yourself in the foot in any language if you try invoking an overridable (virtual) method M of your base class B from within the constructor of B. That's because M is likely to be overridden in derived class D, but at the moment that B is being constructed, D has not been constructed yet. So, D.M is being invoked before the constructor of D has been invoked. That can spell disaster.
So, Java simply allows this to happen, use at your own risk. (If you have sufficient warnings enabled, your compiler will tell you that you are living life dangerously.)
C++ does not prohibit this either, but it slightly changes its behaviour so as to contain the damage, so to speak: when you invoke a virtual method from within a constructor, it does not really invoke it as a virtual method, (with a VMT lookup,) but it invokes it directly, as a non-virtual method.
(Either that, or from within the constructor of B it simply uses class B's VMT instead of D's VMT. Which, come to think of it now, makes sense. But I am not sure about that, it has been a long time since I last troubleshot this behaviour of C++.)

Java Dynamic Binding Confusion

public class Super {
public void methodA() {
System.out.println("super A");
}
public void methodC(Super arg) {
System.out.println("C1");
}
public void methodC(Sub arg) {
System.out.println("C2");
}
} // end class Super
public class Sub extends Super {
public void methodA() {
System.out.println("sub A");
}
public void methodC(Super arg) {
System.out.println("C3");
}
public void methodC(Sub arg) {
System.out.println("C4");
}
} // end class Sub
public class BindingQuestion {
public static void main (String[] args){
Super one = new Super();
Super two = new Sub();
Sub three = new Sub();
two.methodC(three)
}
}
I'm confused as to why two.method(C) returns C4. Isn't two declared as type Super. Shouldn't this mean that it accesses only the Super methods? I thought it would return C2. At least this is what I infered from an answer given to me by #stvcisco in a similar previous question. Dynamic Binding Java. Does an object have the methods of its declared type, or its actual type?
Am I misinterpreting his answer?
The instance method being called depends on the runtime type of the instance.
In Super two = new Sub();, the run time type is Sub (even though the compile time type is Super). Therefore two.methodC(three) calls Sub's methodC(Sub arg).
The compile time type determines the available method signatures that the compiler would accept. Since Super contains a method whose signature matches the call two.methodC(three), this code can pass compilation. However, the actual method that gets invoked is only determines at run time, based on the run time type of two.
Isn't two declared as type Super.
Yes it is.
Shouldn't this mean that it accesses only the Super methods?
No it does not mean this.
What happens is as follows:
At compilation time, the compiler checks if there is a method in Super which can handle methocC(Sub). There are actually two of them. methodC(Super) and methodC(Sub). The compiler selects the most specific signature to be bound at runtime. This one is the methodC(Sub), because Sub is a subclass of Super.
At runtime, the VM looks up for methodC(Sub) in the most specific class possible. This one is Sub, since there is a method defined there with the signature methodC(Sub), therefore this one is bound.
This is because you overwrite the two functions methodC(Super),methodC(Sub).And Super two = new Sub(),this is called polymorphism.It means it would point to the local variable "new Sub()" and the functions in Class Sub though you name it Class Super.And all about this is completing automatically.If you hava a method methodC(Super),methodC(Sub) in Class Super ,yet methodB(Super),methodB(Sub) in Class Sub.The same operation 'Super two = new Sub();two.methodC(Three);will return "C2".In addition, the question you ask is quite common.You need to write more code to understand it.It would be better to write a project with more classes.LikeClass Super;Class Sub1 extends Super;Class Sub2;...,Of course,you can also useInterface`!
Case 1) 'two' is a type of Super class but it contain sub class object. So when you call some method which is defined in both super and sub class then it call the sub class method because sub class has override that method. If it does not found those method in sub class then it call to the super class method.
Case 2) When you remove both of the method ' methodC(Sub arg)' from super and sub class then it call the sub class method 'methodC(Super arg)', if it does not found then it call super class method.
When a sub class object is assigned to super class object then it will
call first sub class method because sub class override super class
method.
What I think is most important while understanding the concept of Dynamic and Static Binding is that many times we think both types of bindings cannot take place within the scope of a program - that both these two are mutually exclusive This is not true. Its just that the two happen at different stages of the program execution and throw an error that time if any ambiguity is found. For example, in your case:
public class BindingQuestion {
public static void main (String[] args){
Super one = new Super();
Super two = new Sub();
Sub three = new Sub();
two.methodC(three)
}
}
During compile time ----------------
When the program is being compiled, the java compiler will traverse through each and every executable code. When it comes to
two.methodC(three)
it will first check if methodC(three) with this signature is available in the class of the type SUPER. Why Super? Because objects in java are accessed through reference. When you do this:
Super two = new Sub();
This means, for the reference two of type Super, you are pointing to an object of SUB. Which is fine. Why? Because in java, a subclasses always have a few extra properties besides the ones implanted into it by its superclass. So from the piece of code above all the properties of SUB which are common with two will work just fine - they will be easily accessed by the reference variable of SUPER type.
So, the compiler checks if the method
After the compiler has executed through the program and not found any ambiguity in terms of the type of the reference matching with the methodC(three) is present in the SUPER class or not.
According to the structure of inheritance that you have provided, is there a method called methodC is the SUPER class. Answer is yes! It does exists. Now, do the arguments match? In other words does the signature match? The answer is yes. Because in SUPER the signature expected in public void methodC(Sub arg). And guess what? Three, is of type SUB. So compiler will pass this line without creating any errors.
Coming to Run time
You must remember that Objects and invoked only and only at runtime. Check of types of methods and signatures is done during compile time.
Now, Java Runtime instance, while invoking the object two, realizes that actually the object two is of SUB class and invokes the method in the SUB class.
Hope this helped.

A call to a static method within the parameter list of super() is valid in Java. Why?

Let's look at the following code snippet in Java.
package trickyjava;
class A
{
public A(String s)
{
System.out.println(s);
}
}
final class B extends A
{
public B()
{
super(method()); // Calling the following method first.
}
private static String method()
{
return "method invoked";
}
}
final public class Main
{
public static void main(String[] args)
{
B b = new B();
}
}
By convention, the super() constructor in Java must be the first statement in the relevant constructor body. In the above code, we are calling the static method in the super() constructor parameter list itself super(method());.
It means that in the call to super in the constructor B(), a method is being
called BEFORE the call to super is made! This should be forbidden by the compiler but it works nice. This is somewhat equivalent to the following statements.
String s = method();
super(s);
However, it's illegal causing a compile-time error indicating that "call to super must be first statement in constructor". Why? and why it's equivalent super(method()); is valid and the compiler doesn't complain any more?
The key thing here is the static modifier. Static methods are tied to the class, instance methods (normal methods) are tied to an object (class instance). The constructor initializes an object from a class, therefore the class must already have been fully loaded. It is therefore no problem to call a static method as part of the constructor.
The sequence of events to load a class and create an object is like this:
load class
initialize static variables
create object
initialize object <-- with constructor
object is now ready for use
(simplified*)
By the time the object constructor is called, the static methods and variables are available.
Think of the class and its static members as a blueprint for the objects of that class. You can only create the objects when the blueprint is already there.
The constructor is also called the initializer. If you throw an exception from a constructor and print the stack trace, you'll notice it's called <init> in the stack frame. Instance methods can only be called after an object has been constructed. It is not possible to use an instance method as the parameter for the super(...) call in your constructor.
If you create multiple objects of the same class, steps 1 and 2 happen only once.
(*static initializers and instance initializers left out for clarity)
Yep, checking the JVM spec (though admittedly an old one):
In the instance init method, no reference to "this" (including the implicit reference of a return) may occur before a call to either another init method in the same class or an init method in the superclass has occurred.
This is really the only real restriction, so far as I can see.
The aim of requiring the super constructor to be invoked first is to ensure that the "super object" is fully initialized before it is used (It falls short of actually enforcing this because the super constructor can leak this, but that's another matter).
Calling a non-static method on this would allow the method to see uninitialized fields and is therefore forbidden. A static method can only see these fields if it is passed this as argument. Since accessing this and super is illegal in super constructor invocation expressions, and the call to super happens before the declaration of any variables that might point to this, allowing calls to static methods in super constructor invocation expressions is safe.
It is also useful, because it allows to compute the arguments to the super constructor in an arbitrarily complex manner. If calls to static methods weren't allowed, it would be impossible to use control flow statements in such a computation. Something as simple as:
class Sub extends Super {
Sub(Integer... ints) {
super(Arrays.asList(ints));
}
}
would be impossible.
This is one situation where the java syntax hides what's really going on, and C# makes it a bit clearer.
In C# your B would look like
class B : A {
public B() : base(method()) {
}
private static String method() {
return "method invoker";
}
}
Although the java syntax places super(method) within the constructor it's not really called there: All the parent initialization is run before your subclass constructor. The C# code shows this a little more clearly; by placing super(method()) at the first line of the java constructor you're simply telling java to use the parameterized constructor of the super class rather than the parameterless version; this way you can pass variables to the parent constructor and they'll be used in the initialization of the parent level fields before your child's constructor code runs.
The reason that super(method()) is valid (as the first line in a java constructor) is because method() is being loaded with the static elements--before the non-static ones, including the constructors--which allows it to be called not only before B(), but before A(String) as well. By saying
public B() {
String s = method();
super(s);
}
you're telling the java compiler to initialize the super object with the default constructor (because the call to super() isn't the first line) and you're ready to initialize the subclass, but the compiler then becomes confused when it sees that you're trying to initialize with super(String) after super() has already run.
A call to super is a must in java to allow the parent to get initalized before anything with child class starts.
In the case above, if java allows String s= method(); before the call to super, it opens up flood gate of things that can be done before a call to super. that would risk so many things, essentially that allows a half baked class to be used. Which is rightly not allowed. It would allow things like object state (some of which may belong to the parent) being modified before it was properly created.
In case of super(method()); call, we still adhere to the policy of completing parent initialization before child. and we can use a static member only, and static member of child classes are available before any child objects are created anyways. so the method is avilable and can be called.
OK..i think, this one could be relevant that, if we are calling some member with Super, then it first try to invoke in super class and if it doesn't find same one then it'll try to invoke the same in subclass.
PS: correct me if i'm wrong

Categories

Resources