Static and dynamic binding logic

I have the following code:

import java.lang.*;

public class Program
{
    public static void main(String [] args) 
    { 
        B a = new A(); 

        a.p(10);  
        a.p(10.0); 
    } 
} 
    class B { 
        public void p(double i) 
        { 
            System.out.println(i*2); 
        } 
    }

    class A  extends B{ 
        public void p(int i) 
        { 
            System.out.println(i); 
        } 
    } 

      

When I execute this code with B a = new A()

, I get 20.0 in both cases, which makes sense because overloading is compile-time processing where the compiler looks at the declared type and calls the function appropriately. Since our declared type was class B, a method of class B was called in both cases. Now if I do A a = new A();

, I should get 10 answers in both answers, but I'm not sure. I get 10 for a.p(10)

and 20.0 for a.p(10.0)

. Based on the concept of static binding and the whole concept of overloading performed by static binding, which looks at the declared type and not the actual type, why is the result obtained this way? I would really appreciate your help.

+3


source to share


7 replies


In your case, you are doing an overload that will bind at compile time (static binding.). Static linking happens to the type of the reference, not the type of the object that the reference points to. In your first case, you are using a reference variable B and assigning object A to it. Since your reference is B, the p (double) method from B will be statically bound even if you are using int (since int can be expanded to double).

In the second case, you are using the link as A. itself. In this case, you have two p () methods available. One is p (double) from B and the other p (int) from A. So p (10) will call p (int) and p (10.0) will call p (double)

Try the following:



class B { 
    public void p(String i) 
    { 
        System.out.println("parent:"+i); 
    } 
}

class A  extends B{ 
    public void p(int i) 
    { 
        System.out.println(i); 
    } 
} 
public class Test1 {
    public static void main(String args[]) {

         A a = new A(); //arg
            a.p(10);  
            a.p("sample"); 
    }
}

      

If you change the line marked arg to B a = new A (), you can see that the compiler tries to call the parent p in both cases.

+1


source


An int

can be expanded to double

, but not vice versa. This means that it 10

can call B.p(double)

or A.p(int)

, but 10.0

is double

and will not be implicitly converted to int

, i.e. Will only be called B.p(double)

.



+2


source


Because your method is p

not an overridden method, it is just nested within your subclass when using

Super sup = new Sub();
sup.p(int);
sup.p(double);

      

In this case, since your Super class has a method that takes a double as a parameter, and a int can fit into a double

, your Super-class method calls the one that takes a double.

Sub sup = new Sub();
sup.p(int);
sup.p(double);

      

In this case, however, since your subclass does not have a method that accepts a double, sup.p(double) call

it uses an inherited method from the superclass for it if you pass double as an argument.

+2


source


When you write A a = new A()

, you are creating a new type object A

that will have 2 methods. A.p(int)

and B.p(double)

, and when you call A.p(10.0)

, it will call B.p(double)

for lack of conversion.

+1


source


This counter example might help:

import java.lang.*;

public class X
{
    public static void main(String [] args) 
    { 
        B c = new A(); 

        c.p(10);  
        c.p(10.0); 
        c.p("AAA");
        ((A)c).p(10);
    } 
} 
    class B { 
        public void p(String s) 
        { 
            System.out.println("B: my string is " + s); 
        } 

       public void p(double i) 
        { 
            System.out.println("B: twice my double is: " + i*2); 
        } 
    }

    class A  extends B{ 
        public void p(int i) 
        { 
            System.out.println("A: my number is " + i); 
        } 
    } 

      

Output:

C:\temp>java X
B: twice my double is: 20.0
B: twice my double is: 20.0
B: my string is AAA
A: my number is 10

      

Problem:

1) You are declaring type "B" (not "A")

2) Bp (10) can take int as floating point argument

3) Hence what you get

It is really a problem of what types of arguments can be implicitly converted, than what methods are overloaded or overridden.

+1


source


When an object has declared a type B

, the version double

is called because it is compatible with the argument int

, since it int

is a subtype in Java double

.

When an object is declared as A

, it has a method p()

overloaded with two versions:

p(int arg);
p(double arg);

      

So when you pass the int

first version is chosen because it is more accurate, and when you pass the double

second because it is the most specific signature.

For reference see the relevant JLS in §15.12.2 and this post by Gilad Brahi . BTW, don't try to figure out how a language should behave based on what you think is the most logical way, because every programming language is an engineering effort, which means there is a price you pay for everything you charge. The main source of information for Java is the JLS, and if you read it carefully, you will (surprisingly?) Find that there are even cases where a string in the source code is ambiguous and cannot be compiled.

+1


source


To make the int expansion effect more striking, I created another example worth looking at. Here, instead, double

I created a class named Parent

and int

a class is created instead Child

.

So
double ~ Parent
int ~ Child

Obviously, a child object can be expanded to a parent reference.

package test;
public class OOPs {
    public static void main(String[] args) {
        Child ch = new Child(); // like int 10
        Parent pa = new Parent();// like double 10.0

        B a = new A(); // case 2 : A a = new A();

        a.p(ch);// 10
        a.p(pa);// 10.0
    }
}

class B {
    public void p(Parent i) {
        System.out.println("print like 20");
        System.out.println(i.getClass().getName());
    }
}

class A extends B {
    public void p(Child i) {
        System.out.println("print like 10");
        System.out.println(i.getClass().getName());
    }
}

class Parent {
    String name;

    Parent() {
        name = "Parent";
    }

    public String getName() {
        return name;
    }
}

class Child extends Parent {
    String name;

    Child() {
        name = "Child";
    }

    public String getName() {
        return name;
    }
}

      

Case 1 - Output (B a = new A();)


print as 20
test.Child
print as 20
test.Parent

Case 2 - Output (A a = new A();)


print as 10
test.Child
print as 20
test.Parent

0


source







All Articles