Java中动态多态和静态多态有什么区别?

149

有人能提供一个简单的例子来说明Java中动态静态多态之间的区别吗?


5
覆盖有时被称为“静态多态”。这有点牵强,但这就是所发生的事情。 - Sergey Kalinichenko
@dasblinkenlight,谢谢你的信息。有没有相关的示例?? - Prabhakar Manthena
搜索"方法重载"和"方法覆盖"。 - Sergey Kalinichenko
7
我不理解重载是如何表现多态性的。多态性是对象的一个概念。我们应该能够把对象B展示为对象A。你在下面的例子中展示了Dog作为Animal,因此它是多态性的。但是在重载中,你调用的是不同的方法,但是使用了“相同的名称”。这怎么能是多态性呢?因此,“静态绑定”是正确的术语,但在重载的情况下,静态多态性并不存在。 - Punith Raj
@PunithRaj 你可能指的是子类型多态性。还有一种叫做特设多态性,适用于重载。 - Kelvin
显示剩余6条评论
14个回答

2

编译时多态性(静态绑定/早期绑定): 在静态多态性中,如果我们在代码中调用一个方法,则该方法的哪个定义实际上将被调用是仅在编译时解决的。

(或)

在编译时,Java通过检查方法签名来确定要调用哪个方法。因此,这被称为编译时多态性或静态绑定。

动态多态性(晚期绑定/运行时多态性): 在运行时,Java等到运行时才确定引用指向的实际对象。由于方法解析是在运行时进行的,因此我们称之为运行时多态性。


1
考虑下面的代码:
public class X
{
    public void methodA() // Base class method
    {
        System.out.println ("hello, I'm methodA of class X");
    }
}

public class Y extends X
{
    public void methodA() // Derived Class method
    {
        System.out.println ("hello, I'm methodA of class Y");
    }
}
public class Z
{
public static void main (String args []) {

    //this takes input from the user during runtime
    System.out.println("Enter x or y");
    Scanner scanner = new Scanner(System.in);
    String value= scanner.nextLine();

    X obj1 = null;
    if(value.equals("x"))
        obj1 = new X(); // Reference and object X
    else if(value.equals("y"))
        obj2 = new Y(); // X reference but Y object
    else
        System.out.println("Invalid param value");

    obj1.methodA();
}
}

现在,仅从代码中你无法确定哪个methodA()的实现将被执行,因为它取决于用户在运行时给出的值。因此,在运行时才决定调用哪个方法。因此,这就是运行时多态性。


1
继Naresh的回答之后,动态多态性在Java中只有在虚拟机存在并且能够在运行时解释代码而不是本地运行代码时才是“动态”的。
在使用gcc编译成本地二进制文件时,C++必须在编译时解决它;然而,在虚拟表中的运行时跳转和thunk仍然被称为“查找”或“动态”。如果C继承B,并且您声明B * b = new C(); b->method1();,则编译器将解析b指向C内部的B对象(对于简单类继承类的情况,C内部的B对象和C将从相同的内存地址开始,因此不需要执行任何操作;它将指向它们都使用的vptr)。如果C继承B和A,则C内部的A对象的虚函数表条目method1将具有一个thunk,该thunk将偏移指针到封装C对象的开头,然后将其传递给C覆盖的真正的A :: method1()文本段。对于C * c = new C(); c->method1(),c已经指向外部C对象,并且指针将传递到文本段中的C :: method1()。参考:http://www.programmersought.com/article/2572545946/ 在Java中,对于B b = new C(); b.method1();,虚拟机能够动态检查与b配对的对象的类型,并传递正确的指针并调用正确的方法。虚拟机的额外步骤消除了虚函数表或类型在编译时被解析的需要,即使在编译时可以知道它。这只是一种不同的方式,在涉及虚拟机且代码仅编译为字节码时是有意义的。

0

方法重载是一种编译时多态性,让我们来举个例子来理解这个概念。

class Person                                            //person.java file
{
    public static void main ( String[] args )
    {
      Eat e = new Eat();
       e.eat(noodle);                                //line 6
    }

   void eat (Noodles n)      //Noodles is a object    line 8                     
   {

   }
   void eat ( Pizza p)           //Pizza is a object
  {

  }

}

在这个例子中,Person类有一个eat方法,表示他可以吃比萨或面条。当我们编译Person.java时,方法eat被重载了,编译器会将第6行的方法调用“e.eat(noodles)”解析为第8行指定的以noodles作为参数的方法定义,整个过程由编译器完成,因此它是编译时多态性。 将方法调用替换为方法定义的过程称为绑定,在这种情况下,由编译器完成,因此称为早期绑定。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接