【问题标题】:What is virtual method calling in java?java中的虚方法调用是什么?
【发布时间】:2012-03-16 06:11:23
【问题描述】:

我在一些计算机科学测试中看到了下一段,我希望我能在这里很好地解释它的含义,因为我用谷歌搜索了一个小时,但找不到任何东西..

“当我们说 Java 语言有虚拟方法调用时,我们的意思是在 Java 应用程序中,执行的方法是由运行时的对象类型决定的”

这是什么意思?谁能更好地解释一下?

【问题讨论】:

标签: java methods runtime


【解决方案1】:

这些行的作者使用了virtual 的c++ 术语。

更好的术语是dynamic binding / dynamic dispatch

这意味着,对象的动态type 正在“选择”将调用哪个方法,而不是静态类型。

例如:[伪代码]:

class A {
  public void foo() { }
}
class B extends A { 
  public void foo() { }
}

调用时:

A obj = new B();
obj.foo();

将调用B.foo(),而不是A.foo(),因为obj 的动态类型是B

【讨论】:

  • 只是一个需要澄清的问题:如果 B 中的 foo 方法具有不同的签名,例如public void foo(int i) {} 那么A.foo() 会被选中吗?
  • @VanTheMan 是的,在这种情况下不会超载
  • 或者实际上,您的意思是在这种情况下该方法不是覆盖吗?据我了解,重载是指同名但参数不同的方法。而覆盖是指继承的方法具有相同的名称相同的签名。
【解决方案2】:

我们的意思是在java应用程序中执行的方法是由运行时的对象类型决定的

interface Animal{
  public void eat();
}


class Person implements Animal{
   public void eat(){ System.out.println("Eating Food");}
}



class Eagle implements Animal{
   public void eat(){ System.out.println("Eating Snake");}
}

主要

Animal animal = new Person();
animal.eat(); //it will print eating food
animal = new Eagle();
animal.eat(); //it will print eating snake

【讨论】:

  • 谢谢!!我想我知道,但如果我错了,请纠正我:所以说“在java应用程序中,执行的方法由运行时的对象类型确定”,这意味着java仅在执行时确定对象?在您的示例中,animal.eat(第一个)将执行 Person 的方法,第二个它将执行 Eagle 的方法,这就是它的目的吗?
  • 没错,对象将被创建运行时,所以它是运行时决定
【解决方案3】:

假设你有一个 Fruit 类,它有两个子类 Orange 和 Banana。并假设 Fruit 有一个 String getColor() 方法。

Orange 可以覆盖getColor() 方法以返回“橙色”。 Banana 也一样,它可以返回“黄色”。

当某个方法使用 Fruit 类型的对象,并调用 getColor() 方法时,如果 Fruit 的类型实际上是 Banana,将调用的方法是 Banana.getColor()

 private void printColor(Fruit f) {
     System.out.println(f.getColor());
 }

 ...

 Fruit fruit1 = new Banana();
 Fruit fruit2 = new Orange();
 printColor(fruit1); // prints yellow
 printColor(fruit2); // prints orange     

【讨论】:

  • 谢谢 :) 我在前面的帖子中得到了答案,但这也是一个很好的解释。
【解决方案4】:

Employee.java

public class Employee
{
   private String name;
   private String address;
   private int number;
   public Employee(String name, String address, int number)
   {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   public void mailCheck()
   {
      System.out.println("Mailing a check to " + this.name
       + " " + this.address);
   }
}

VirtualMethod.java

class Salary extends Employee
{
   private double salary; //Annual salary
   public Salary(String name, String address, int number, double
      salary)
   {
       super(name, address, number);
       this.salary=salary;
   }
   public void mailCheck()
   {
       System.out.println("Within mailCheck of Salary class ");
       System.out.println("Mailing check to " 
       + " with salary " + salary);
   }

}

public class VirtualMethod
{
   public static void main(String [] args)
   {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
      System.out.println("Call mailCheck using Salary reference --");
      s.mailCheck();
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
    }
}

输出

Constructing an Employee
Constructing an Employee
Call mailCheck using Salary reference --
Within mailCheck of Salary class
Mailing check to  with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to  with salary 2400.0

说明

在这里,我们实例化了两个Salary 对象。一个使用Salary 引用s,另一个使用Employee 引用e

在调用s.mailCheck() 时,编译器会在编译时看到Salary 类中的mailCheck(),而JVM 在运行时调用Salary 类中的mailCheck()

e 上调用mailCheck() 完全不同,因为eEmployee 引用。当编译器看到e.mailCheck() 时,编译器会看到Employee 类中的mailCheck() 方法。

这里,在编译时,编译器使用mailCheck() in Employee 来验证这个语句。但是,在运行时,JVM 会调用 Salary 类中的 mailCheck()

【讨论】:

  • 我知道这只是一个例子,但“class Salary extends Employee”不是建模。薪水不是雇员。
猜你喜欢
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-01
  • 2013-02-01
相关资源
最近更新 更多