简体   繁体   中英

How does Java determine what method to invoke by implicit type invokations?

This problem presented itself when me and my friends were studying for exams. We noticed strange behavior when calling a statically assigned variable's method.

Code>Words so here we go:

class C {

    public void a(double x) {}
}

class D extends C {
    void b() {} 
}

class F extends D {

    void a(int i) {} 
    void a(double d) {} 

Now, doing

D foo = new F();
foo.a(1);

What will this give? Well.. it runs method a(double) in F !!

This is what we thought happened:

  1. Program start by looking for a in static type D : nothing there.
  2. Goes to its super class, C . Does not find a(int) but instead finds a(double) .
  3. Decides that this is the signature i meant (ie a(double)), but FIIRST, after all this search let's look at the dynamic type first it says!
  4. Runs a(double) in F!

Is this correct? This means that it climbed the hierarchy to find some method that could fit if type conversion from int to double is done.. AFTER this it checks to see if the dynamic type has this newly interpreted signature.

I noticed that if I added

void a(int) {}

** in class C , it would give me a(int) in F when running the invocation above!

Can someone please explain the mechanics involved in this process? Why is so that the code runs/compiles this way? What's the technical reasons behind this? And are there any more things one should be aware of concerning similar cirumstances ()

The reason is because Java is statically typed. Dispatch on argument type is done at compile time, not runtime.

When the code is compiled, the compiler sees that you are invoking a method named a on an object of static type D . It looks for compatible methods in D , and finds a single method (inherited from C ). It generates code to perform a virtual call to Ca(double) .

At runtime, the virtual call dispatches on the actual type of the object (not the arguments!), so it ends up calling Fa(double) , since this overrides Ca(double) .

The fact that the runtime type of the object is F and F happens to have a different method that would have been valid if it were known at compile time is irrelevant. If you want this behavior, you need reflection.

If you added Ca(int) , the compiler would see two different methods named a in D , and based on the overloading rules, choose the one that takes an int.

The method to call is resolved at compile time, not runtime. Since the compiler only knows at compile time that foo is a D , and therefore only has a method a(double) , that is the method which is called. Precisely which object's a(double) to call is done dynamically (at runtime) however, which is why Fa(double) will be called and not Ca(double) .

This is called single dispatch : the method to call is dynamic on the object it is being invoked on, but static on its argument types.

If you removed that method in C entirely, it wouldn't call a(int) in F , it would just fail to compile saying that it can't find that method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM