Java确定方法如何在运行时调用多态? [英] How does Java Determine methods call at runtime in polymorphism?

查看:151
本文介绍了Java确定方法如何在运行时调用多态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然多态性的主要原则是在类型的术语中将什么与谁分离,但令我困惑的是方法调用机制如何找出并调用正确的多态中的方法体。

While the main principle of polymorphism is decoupling "what from who" in term of types, but what confuses me how does method-call mechanism finds out and calls the correct method body in polymorphism.

因为在java中,所有方法绑定都是后期绑定,除非方法是 static final private ,后期绑定由JVM完成为每个类预先计算方法表,然后在正常方法调用的运行时期间查找表。

Since in java all method binding is late-binding unless the method is static, final or private, and late-binding is done by JVM which precomputes method table for each class and then do a table look up during runtime in normal method call.

但是在多态性过程中也会发生同样的事情。例如

But the same thing happens during polymorphism too. For example

假设我有一个Generic类 Cycle ,带有 ride() method

Suppose I've a Generic class Cycle with a ride() method

class Cycle {

    public void ride(){
        System.out.println("I'm Riding generic Cycle()");
    }

}

我有三个专业类 Bicycle Tricycle Unicycle 扩展了Generic class 循环并覆盖其 ride()方法。

And i have three Specialized Class Bicycle Tricycle and Unicycle which extends Generic class Cycle and overrides its ride() method.

class Bicycle extends Cycle {

    public void ride() {
        System.out.println("I'm riding Bicycle");

    }

}

class Tricycle extends Cycle{

    public void ride() {
        System.out.println("I'm riding Tricycle ");

    }

}

class Unicycle extends Cycle {

    public void ride() {
        System.out.println("I'm Riding Unicycle ");

    }

}

这是 TestRide 用于测试上述多态性的类。

This is the TestRide class to Test the above Polymorphism.

public class TestRide {

    public static void ride(Cycle c){
        c.ride();
    }

    public static void main(String[] args){

        Cycle Cycling = new Cycle();
        ride(Cycling);

        Bicycle bi = new Bicycle();
        ride(bi);

        Tricycle tri = new Tricycle();
        ride(tri);

        Unicycle uni = new Unicycle();
        ride(uni);
    }

}

输出

I'm Riding generic Cycle()
I'm riding Bicycle
I'm riding Tricycle 
I'm Riding Unicycle 

字节代码:

public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
         0: new           #17                 // class com/polymorphism/Cycle
         3: dup
         4: invokespecial #24                 // Method com/polymorphism/Cycle."
<init>":()V
         7: astore_1
         8: aload_1
         9: invokestatic  #25                 // Method ride:(Lcom/polymorphism/
Cycle;)V
        12: new           #27                 // class com/polymorphism/Bicycle
        15: dup
        16: invokespecial #29                 // Method com/polymorphism/Bicycle
."<init>":()V
        19: astore_2
        20: aload_2
        21: invokestatic  #25                 // Method ride:(Lcom/polymorphism/
Cycle;)V
        24: new           #30                 // class com/polymorphism/Tricycle

        27: dup
        28: invokespecial #32                 // Method com/polymorphism/Tricycl
e."<init>":()V
        31: astore_3
        32: aload_3
        33: invokestatic  #25                 // Method ride:(Lcom/polymorphism/
Cycle;)V
        36: new           #33                 // class com/polymorphism/Unicycle

        39: dup
        40: invokespecial #35                 // Method com/polymorphism/Unicycl
e."<init>":()V
        43: astore        4
        45: aload         4
        47: invokestatic  #25                 // Method ride:(Lcom/polymorphism/
Cycle;)V
        50: return

即使在字节码中,它就像通常的方法调用 invokestatic invokespecial 而我认为它会使用 invokedynamic 以确定适合实际对象类型的方法版本。但事实并非如此。

Even in the bytecode its just as usual method call with invokestatic and invokespecial while i thought it would use invokedynamic to figure out the version of the method that is appropriate for the actual type of the object. But that was not the case.

那么Java如何在多态性中找出实际的方法调用,而我们只是在 ride() 中的方法(bi) TestRide 类?

So how does Java figure out the actual method call during polymorphism while we just pass an upcasted Object in the ride() method like ride(bi) in TestRide class ?

编辑:RIDE方法ByteCode

RIDE method ByteCode

public static void ride(com.polymorphism.Cycle);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokevirtual #16                 // Method com/polymorphism/Cycle.r
ide:()V
         4: return


推荐答案

首先关闭 invokedynamic 是针对Java 8 lambdas和非Java代码的,所以你可以忘记这一点。

First off invokedynamic is for Java 8 lambdas and non-Java code, so you can forget about that.

除此之外,还有四个调用指令( invokespecial invokestatic invokevirtual invokeinterface )。您可以在JVM sepcification中看到精确的语义,但最重要的是 invokevirtual invokeinterface 虚拟方法调用,即调用的实际方法是在运行时根据目标的conrete类型选择的。

Apart from that, there are four invoke instructions (invokespecial, invokestatic, invokevirtual, and invokeinterface). You can see the precise semantics in the JVM sepcification, but the bottom line is that invokevirtual and invokeinterface are virtual method calls, i.e. the actual method called is chosen at runtime based on the conrete type of the target.

代码中唯一的虚拟调用是TestRide.ride。列出的目标是 Cycle.ride :()V 。但是,由于它是一个虚拟调用,JVM将在运行时检查第一个参数的实际类型,并调用该方法的派生版本。

The only virtual call in your code is in TestRide.ride. The listed target is Cycle.ride:()V. However, since it is a virtual call, the JVM will check the actual type of the first argument at runtime and call the most derived version of that method.

这是类似的使用C ++进行虚拟方法调用,除了JVM和JIT编译的抽象允许更多优化实现的可能性。

This is similar to virtual method calls in C++, except that the abstraction of the JVM and JIT compilation allows the potential for more optimized implementations.

另请注意,这不应与方法重载,这是一种编译时多态。对于重载方法,编译器根据参数的编译时类型选择调用哪一个。

Also note that this is not to be confused with method overloading, which is a form of compile-time polymorphism. For overloaded methods, the compiler chooses which one to call based on the compile time type of the arguments.

这篇关于Java确定方法如何在运行时调用多态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆