【问题标题】:Why aren't Java fields polymorphic?为什么 Java 字段不是多态的?
【发布时间】:2017-09-10 10:53:32
【问题描述】:

我正在查看this 的答案,但我不明白为什么方法是多态的而不是字段的背后的逻辑。

默认情况下,Java 中的所有成员函数都是多态的。这意味着 当你调用 this.toString() Java 使用动态绑定来解决 call,调用子版本。当您访问成员 x 时,您 访问您当前范围的成员(父亲),因为成员 不是多态的。

当您在父类和子类中都有一些字段x,并在您的子类中覆盖toString,当您在基类中调用以下内容时:

System.out.println(this); //calls the subclass's toString implementation
System.out.println(this.x) //prints the base class's x field

在开头链接的问题中列出的答案中的理由是,当基类在其自己的范围内时,基类不“知道”子类,但是对于多态性,它是同一件事:超类不知道子类存在,但仍然调用子类方法。那么,Java 究竟做了什么让两者的行为有所不同——一种在子类中使用动态绑定,另一种保持超类的范围?

编辑:澄清一下,我不知道为什么 this.x 会做与多态性相同的事情,查看对象的实际类型,而不仅仅是引用类型,并从子类中打印 x 字段.

【问题讨论】:

  • “班级成员”是指“字段”吗?如果是这样,那就更清楚了。方法也是“成员”...
  • @JonSkeet,是的,谢谢。我修好了。
  • 从根本上说,每次声明一个新字段时,都会添加更多状态。如果你重写一个方法,你不是在添加一个新方法,你是在替换一个现有签名的实现。任何时候您想要对字段使用“多态性”,可能有更好的设计可以使用...
  • @rb612 我认为(但我可能非常错误),这是因为 x 存储在实例级别,而方法存储在类级别。而 superInstance 根本不存在。您可以从子类调用超类,但是在子类 Instance 中存储 super.x 很奇怪。
  • @JonSkeet 谢谢你的回答,很荣幸得到你的解释!现在在回答最初的问题时给出的解释,即父类不“知道”子类,对我来说没有意义。不是说有了this.x,Java应该马上看到this这个关键字,就意识到它其实是一个子实例,然后调用相应的方法,就像多态一样?或者在 this 上调用方法与访问字段时是否有一些不同的过程?

标签: java oop inheritance


【解决方案1】:

为了实现子类型多态,Java 需要跟踪调用哪个方法,这需要额外的开销。您可以通过保持字段私有并使用 getter 来实现某种“多态字段”(前者不是必需的,但这样做是明智的)。您可能有兴趣查看

  • 动态调用
  • 调用接口
  • 调用特殊
  • 调用静态
  • 调用虚拟

来电。你可以在这里阅读更多关于它的信息: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokevirtual

【讨论】:

  • 谢谢!我更好奇为什么方法是多态的而不是字段。
  • 我想我应该强调 需要额外的开销 :)。让我们从颠倒您的问题开始:为什么访问字段需要多态机制?对于方法,可以通过声称子类型多态性是 OOP 世界中功能扩展的基本机制之一来证明这一点。因此,让我们为非私有方法添加 invokevirtual 功能(与默认功能不同:仅访问当前对象的方法),并在调用此类方法时接受开销。我们是否应该为每个字段解析接受这样的开销,而在需要时可以设置/获取?
猜你喜欢
  • 2010-10-28
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
相关资源
最近更新 更多