2017-09-07 85 views
1

我想澄清一些关于绑定和调度的问题。静态/动态绑定和静态/动态调度有点令人困惑

绑定将方法调用附加到方法签名。调度正在选择方法实现。首先绑定,然后派遣。好的,我得到了这个,但是:

  1. 未被覆盖的实例方法是否使用静态绑定?
  2. 为什么重载方法使用静态绑定,因为它们是虚拟的,可以在子类中重写?

我在过去的几天里看过很多的解释,现在对我来说是一团糟。其中有些是互相冲突或完全相反的。从我知道的所有非static,非private和非final在Java中的方法默认是虚拟的,并且必须使用动态绑定和动态分派。

+0

1号堂妹可能被别人取代。编译器不会知道一个方法没有被覆盖。例外是私有方法和最终方法,至少前者是静态绑定的。 2.什么让你觉得“重载方法使用静态绑定”? –

回答

1

绑定将方法调用附加到方法签名。调度正在选择方法实现。

绑定意义上的意思是指超载。在你的意思是指覆盖的意义上调度。

先来绑定,然后发送。

是的。编译器执行绑定,JVM进行分派。

OK,我得到了这一点,但:

  1. 难道还没有被覆盖使用静态绑定实例的方法呢?

号编译器不能告诉,除了在privatefinal方法的情况。

  • 为什么究竟重载方法使用静态绑定,因为它们是虚拟并且可以在子类覆盖?
  • 他们没有。

    从我所知道的所有非静态,非私有和非最终的Java方法在默认情况下都是虚拟的,并且必须使用动态绑定和动态分派。

    正确。

    +0

    现在我明白重载的方法是虚拟的,它在运行时使用动态绑定,但是:3)重载方法使用静态绑定绑定,而重写的方法在运行时使用动态绑定绑定。这是什么意思? –

    +0

    @violet_eyes我见过这样的说法:“重载的方法使用静态绑定绑定,而重写的方法在运行时使用动态绑定绑定”。在很少的博客上,但这种说法并不总是正确的。这完全取决于方法被调用和声明的方式。你可以看到我在答案中提供的案例,重载方法是动态绑定的。 –

    +0

    这部分看起来不对:_No。除了private或final方法外,编译器不能说明这一点._只有一个字节码:'invokevirtual'在编译时调用非静态非接口方法,即使是'private/final'方法,所以编译时的行为是一样的。在运行时编译(JIT)期间,'final'和'private'也不会帮助任何现代JVM确定是否存在重写方法,无论是否存在final或private。所以在实践中,这些限定符不会改变编译或运行时的行为。 – BeeOnRope

    0

    规则对Java绑定:

    1)调用一个静态方法是静态绑定。

    2)调用构造函数是静态绑定的。

    3)呼叫,以非静态方法是动态绑定:

    例外: 3.A)调用私有的,非静态方法是静态绑定。

    3.b)在子类中调用使用super的非私有非静态方法也是静态绑定的。

    因此对于第一个问题即没有被覆盖的实例方法是否使用静态绑定?

    答案是No.如果该方法没有被覆盖,但它可以(将来)。因为它是一个实例方法,所以它可以使用实例(动态绑定)或使用超级(静态绑定)调用。

    第二个问题:为什么重载方法使用静态绑定,因为它们是虚拟的,可以在子类中重写?

    答案:没有这样的事情,重载的方法是静态绑定的。

    说明:

    class Sample{ 
    
        public void method1(){ 
         System.out.println("hello from A"); 
        } 
    
        public void method1(String user){ 
         System.out.println("hello "+user+" from overloaded method"); 
        } 
    
         public static void main(String []argh){ 
         Sample s = new Sample(); 
         s.method1(); 
         s.method1("name"); 
        } 
    } 
    

    在上面的代码中,该方法method1()过载,但因为它既不是静态的,最终也不私有的,所以它产生invokevirtual指令,这意味着它被动态地绑定不是静态的。

    要清除的结合的差异,调度是指这个Question

    +1

    'final'方法在编译时不是静态绑定的。试试这个[实验](https://gist.github.com/travisdowns/92e85659cc9680df82fb0b9a98e11193)。把'Base','Derived'和'Print'放在自己的文件中,用'javac'编译'Base'和'Print'。现在'Print.printBase'应该是_statically绑定到'Base.print()'的调用,因为这个调用是'final'。将'Print.class'移到某处,然后从'Base.print()'中移除'final'修饰符。编译'Derived'(这也将编译'Base'和'Print',因为'javac'编译依赖关系 – BeeOnRope

    +0

    最后,拷贝最初编译的'Print.class'版本'静态绑定'版本(替换最新的)。在Derived中运行'main()',注意它打印出了''derived''。尽管打印是在最后的Base.print()中编译的,但是没有静态绑定,你可以用'javap ' - 生成的字节码使用'invokevirtual'来调用'print()' - 不管被调用的方法是final还是not_。事实上,这是用于调用非静态非接口方法的_only_字节码,所以不能在编译的时候是静态绑定的东西 – BeeOnRope

    +0

    以前我没有在我的答案中写'final',但后来有些书让我困惑,在Java中,Complete引用它提到“由于final方法不能被覆盖,一个调用可以在编译时解决,这叫做早期绑定“,a另外,在“Thinking in Java”中,“Java中的所有方法绑定使用后期绑定,除非方法是静态或最终的” 感谢您明确绑定不依赖于“final”。 –