简体   繁体   English

多态性在 Java 中的方法参数中不起作用

[英]Polymorphism doesn't work in method arguments in Java

I wrote the following piece of code:我写了下面的一段代码:

class Plane {}
class Airbus extends Plane {}

public class Main {

    void fly(Plane p) {
        System.out.println("I'm in a plane");
    }

    void fly(Airbus a) {
        System.out.println("I'm in the best Airbus!");
    }

    public static void main(String[] args) {

        Main m = new Main();

        Plane plane = new Plane();
        m.fly(plane);

        Airbus airbus = new Airbus();
        m.fly(airbus);

        Plane planeAirbus = new Airbus();
        m.fly(planeAirbus);

    }
}

And the result is:结果是:

I'm in a plane
I'm in the best Airbus!
I'm in a plane

Unsurprisingly the two first invocations give I'm in a plane and I'm in the best Airbus!不出所料,前两次调用让I'm in a planeI'm in the best Airbus! respectively.分别。

Plane planeAirbus = new Airbus();

The method treats this object as a Plane, even though the real object is an Airbus.该方法将此对象视为飞机,即使真实对象是空客。 Even when I add abstract to class Plane , nothing changes and the result of last invocation is still I'm in a plane即使我将abstract添加到class Plane ,也没有任何变化,上次调用的结果仍然I'm in a plane

So the question is why polymorphism doesn't work in method arguments and invocations?所以问题是为什么多态在方法参数和调用中不起作用? Is there any purpose of that?这样做有什么目的吗? How does it work?它是如何工作的?

The problem here is that Java does not support dynamic binding of method arguments.这里的问题是 Java 不支持方法参数的动态绑定。 What you see is static binding, ie the overload of the method to call is chosen at compile time.您看到的是静态绑定,即在编译时选择要调用的方法的重载。

See also: Static Binding and Dynamic Binding另请参阅: 静态绑定和动态绑定

Method overloading type polymorphism is determined at the compile time in Java.方法重载类型多态性是在 Java 编译时确定的。

Meaning that Java has to infer type of the method parameters from the reference type they represent, as it has no idea about the type of object they hold at the compile time. 这意味着 Java 必须从它们表示的引用类型推断方法参数的类型,因为它不知道它们在编译时持有的对象类型。

We can argue that it's pretty clear in this case that reference of Plane type holds Airbus type instance.我们可以争辩说,在这种情况下,很明显 Plane 类型的引用包含 Airbus 类型实例。 However it's not that simple, as the Airbus instance itself could have been a method parameter, which could hold any subclass instance or Airbus instance itself.然而事情并没有那么简单,因为 Airbus 实例本身可能是一个方法参数,它可以包含任何子类实例或 Airbus 实例本身。

Only safe bet is to not parse through the parent chain and take the reference for it's face value that is actual reference variable type.唯一的安全赌注是不解析父链并获取它的实际引用变量类型的面值的引用。 Another way of doing this could have been by implementing method overloading same as overriding and by using run time binding of objects for resolution.另一种方法可能是通过实现与覆盖相同的方法重载并使用对象的运行时绑定进行解析。 I don't know why it wasn't done this way as it would have made method overloading and overriding more uniform.我不知道为什么不这样做,因为它会使方法重载和覆盖更加统一。

Following are the references from JLS Overloading以下是JLS 重载的参考资料

When a method is invoked (§15.12), the number of actual arguments (and any explicit type arguments) and the compile-time types of the arguments are used, at compile time, to determine the signature of the method that will be invoked (§15.12.2). 调用方法时(第 15.12 节),在编译时使用实际参数(和任何显式类型参数)的数量和参数的编译时类型来确定将被调用的方法的签名(第 15.12.2 节)。 If the method that is to be invoked is an instance method, the actual method to be invoked will be determined at run time, using dynamic method lookup (§15.12.4). 如果要调用的方法是实例方法,则将在运行时使用动态方法查找(第 15.12.4 节)确定要调用的实际方法。

Java overloading is compile time polymorphism. Java 重载是编译时多态性。 So, when you declare planeAirbus as Plane , it will invoke fly(Plane) .因此,当您将planeAirbus声明为Plane ,它将调用fly(Plane)

In fact, class Main shouldn't know than Plane and Airbus can fly.实际上, Main班不应该知道PlaneAirbus可以飞。 Better design of it:更好的设计:

public interface Flyable{
  void fly();
}

public Plane implements Flyable{
  void fly(){
     //do something
  }
}

 public Airbus implements Flyable{
    void fly(){
       //do something
    }
 }

And then in Main class然后在Main

public static void main(String[] args) {
  Flyable plane = new Plane();
  plane.fly();

  Flyable airbus = new Airbus();
  airbus.fly();
}

Reason for the outputs following output:输出以下输出的原因:

I'm in a plane
I'm in the best Airbus!
I'm in a plane

Because it is performing overloading, and overloading is Static polymorphism or Compile Time Polymorhism.因为它在执行重载,而重载是静态多态或编译时多态。 In overloading, class can have more than one methods with same name but different types of arguments.在重载中,类可以有多个名称相同但参数类型不同的方法。 In your example Plane is type for Plane planeAirbus = new Airbus();在您的示例中, Plane的类型为Plane planeAirbus = new Airbus();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM