【问题标题】:Static Binding and Dynamic Binding静态绑定和动态绑定
【发布时间】:2013-05-20 10:33:04
【问题描述】:

我真的对动态绑定和静态绑定感到困惑。我读过在编译时确定对象的类型称为静态绑定,在运行时确定对象类型称为动态绑定。

下面的代码发生了什么:

静态绑定还是动态绑定?
这表明了什么样的多态性?

class Animal
{
    void eat()
    {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal
{
    void eat()
    {
        System.out.println("Dog is eating");
    }
}

public static void main(String args[])
{
    Animal a=new Animal();
    a.eat();
}

【问题讨论】:

  • 你的 a.eat() 不应该在 main 方法里面吗?
  • 尽快阅读“Head first core java”。
  • 这更多的是dynamic binding

标签: java oop polymorphism dynamic-binding static-binding


【解决方案1】:

您的示例是动态绑定,因为在运行时会确定a 的类型,并调用相应的方法。

现在假设您也有以下两种方法:

public static void callEat(Animal animal) {
    System.out.println("Animal is eating");
}
public static void callEat(Dog dog) {
    System.out.println("Dog is eating");
}

即使您将 main 更改为

public static void main(String args[])
{
    Animal a = new Dog();
    callEat(a);
}

这将打印Animal is eating,因为对callEat 的调用使用静态绑定,而编译器只知道a 的类型为Animal

【讨论】:

  • @Heuster 感谢这样一个很好的例子。但是你能告诉我我的代码表现出什么样的多态性吗?静态多态还是运行时多态?
  • 嗯,你没有指定它真的依赖于覆盖/重载。但很好的答案:-)
  • @user2401175 正如 Muhammad Ramahy 刚刚提到的:您覆盖Animal 的方法 eat。这使用动态绑定。在我的第二个示例中,我使用多个签名重载方法callEat。这使用静态绑定。
  • @VincentvanderWeele 那么这是否意味着如果有方法重载,它总是静态绑定,如果有方法覆盖,那么绑定将是动态的?
【解决方案2】:

这真的取决于重载覆盖如果你做了这样的事情:

public class Animal{}


public class Dog extends Animal{}

public class AnimalActivity{

    public void eat(Animal a){
        System.out.println("Animal is eating");
    }

    public void eat(Dog d){
        System.out.println("Dog is eating");
    }
}

然后在主类中:

public static void main(String args[])
{
    Animal a=new Animal();
    Animal d=new Dog();
    AnimalActivity aa=new AnimalActivity();
    aa.eat(a);
    aa.eat(d);
}

这两种情况的结果将是:Animal is eating

但让我们扭曲一下,让我们拥有这个:

public class Animal{
    public void eat(){
        System.out.println("Animal is eating");
    }
}

然后:

public class Dog extends Animal{
    public void eat(){
        System.out.println("Dog is eating");
    }
}

然后在主类中:

public static void main(String args[]){
    Animal d=new Dog();
    Animal a=new Animal();
    a.eat();
    d.eat();
}

现在结果应该是:

Animal is eating
Dog is eating

这是因为在编译时重载绑定“静态绑定” 在运行时覆盖绑定时“动态绑定”

【讨论】:

    【解决方案3】:

    您当前的代码将输出 Animal is eating

    但是,在您的主类中,如果您创建了一个Dog 类型的对象并将其分配给Animal,那么由于动态绑定,您的输出将为Dog is eating

    public static void main(String args[])
    {
        Animal a = new Dog(); // An object of Dog is assigned to Animal
        a.eat(); // Dynamically determines which eat() method to call
    }
    

    即使a 被声明为Animal,它也指向Dog 类型的对象。因此,在运行时,会确定对象类型并调用适当的eat() 方法。

    一种思考方式是,method overloading 是静态绑定的,method overriding 是动态绑定的。

    【讨论】:

    • 那么,你是说我的代码展示了静态绑定吗?
    • @user2401175 没有。答案是“由于动态绑定”。因此代码显示了动态绑定的示例,因为eat() 方法是在运行时选择的,基于调用它的动物(狗)的具体类型,而不是变量(动物)的声明类型.
    • @srikanta:您的评论与您的​​回答相矛盾。 OP的代码与您的相同。要调用的 eat() 方法是根据动物的具体运行时类型动态确定的。唯一的区别是 OP 的 animal 是 Animal 的一个实例,而你的是 Dog 的一个实例。
    【解决方案4】:

    对于非静态函数,只要函数是非虚拟的,即应用 final 关键字和/或函数是 private,就使用静态绑定。 final 表示该函数不能更改,private 关键字表示它仅具有类作用域。否则,使用动态绑定。

    对于静态函数,总是使用静态绑定。如果传入了A 类型,它将运行A 的方法,而不管A 引用的位置。

    【讨论】:

      【解决方案5】:

      案例一:

      Animal a =new Animal();
      a.eat();
      

      案例 2:

      Animal a=new Dog(); 
      a.eat();
      

      这里都是动态绑定,因为在编译时对象的类型是确定的,但在运行时基于实例,分配了相应eat方法的对象将由JVM动态绑定。

      在第一种情况下调用了动物类的eat方法,而在第二种情况下,调用了狗类的eat方法,因为Animal对象被分配了一个Dog实例。Dog的实例也是animal的实例。也就是说你可以把它当成“is a”关系狗是动物。所以这里的对象类型在运行时被确定为狗,JVM动态绑定狗类的eat方法。

      也检查此链接

      http://www.javatpoint.com/static-binding-and-dynamic-binding

      http://www.coderanch.com/t/386124/java/java/Static-Binding-Dynamic-Binding

      【讨论】:

      • 谢谢,但你能告诉我我的代码表现出什么样的多态性吗?是静态多态还是运行时多态?
      • 这是完全错误的。 JVM 在运行时根据对象的具体运行时类型选择必须调用的可覆盖方法。无论对象是声明类型的实例还是子类型的实例都不会改变任何事情:绑定是动态的。
      • @user2401175 it case 1 它是编译时多态性和 case2 :它是运行时检查这个链接我认为它回答了你的问题stackoverflow.com/q/2152848/2006839
      • @JBNizet 我所说的编译器是 JVM 应该使用正确的术语来编辑我的答案。
      【解决方案6】:

      检查这个 员工类有抽象的earning()函数,每个类都有不同的toString()实现

      Employee[] employees = new Employee[4];
      
      // initialize array with Employees
      employees[0] = new SalariedEmployee();
      employees[1] = new HourlyEmployee();
      employees[2] = new CommissionEmployee();
      employees[3] = new BasePlusCommissionEmployee();
      for (Employee currentEmployee : employees){
          System.out.println(currentEmployee); // invokes toString
          System.out.printf("earned $%,.2f%n", currentEmployee.earnings());
      }
      

      对方法 toStringearnings 的所有调用都在 execution time 处解析,基于 currentEmployee 所引用的 type of the object

      此过程称为dynamic bindinglate binding

      参考:Java™ How To Program (Early Objects), Tenth Edition

      【讨论】:

        猜你喜欢
        • 2012-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-14
        • 2016-04-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多