Scala程序中如何实现多态和动态绑定
创始人
2024-04-19 02:51:12
0

在10.4节中你看到了类型Element的变量可以指向类型ArrayElement的对象。这种现象的名字叫多态:polymorphism,是指“许多形状”或“许多形式”的意思。这种情况下,Element对象可以有许多形式。这种类型的多态被称为子类型化多态:subtyping polymorphism。Scala里另一种类型的多态,称为统一多态:universal polymorphism,将在第19章讨论。目前为止,你已经看到了两种形式:ArrayElement和LineElement。你可以通过定义新的Element子类创造Element的更多形式。例如,下面定义了拥有给定长度和高度并被指定字符充满的新的Element形式:

  1. class UniformElement(  
  2.  ch: Char,  
  3.  override val width: Int,  
  4.  override val height: Int  
  5. ) extends Element {  
  6.  private val line = ch.toString * width  
  7.  def contents = Array.make(height, line)  
  8. }  

布局元素的类层级

图释 10.3 布局元素的类层级

51CTO编辑推荐:Scala编程语言专题

类Element的继承层级现在看上去如图释10.3展示的样子。结果,Scala将接受所有的下列赋值,因为赋值表达式的类型符合定义的变量类型:

  1. val e1: Element = new ArrayElement(Array("hello", "world"))  
  2. val ae: ArrayElement = new LineElement("hello")  
  3. val e2: Element = ae  
  4. val e3: Element = new UniformElement('x', 2, 3)  
若你检查继承层级,你会发现这四个val定义的每一个里,等号右侧表达式的类型都在将被初始化的等号左侧的val类型之下。

然而,另一半的故事是,变量和表达式上的方法调用是动态绑定:dynamically bound的。这意味着被调用的实际方法实现取决于运行期对象基于的类,而不是变量或表达式的类型。为了演示这种行为,我们会从我们的Element类中临时移除所有存在的成员并添加一个名为demo的方法。我们会在ArrayElement和LineElement中重载demo,但UniformElement除外:

  1. abstract class Element {  
  2.  def demo() {  
  3.   println("Element's implementation invoked")  
  4.  }  
  5. }  
  6. class ArrayElement extends Element {  
  7.  override def demo() {  
  8.   println("ArrayElement's implementation invoked")  
  9.  }  
  10. }  
  11. class LineElement extends ArrayElement {  
  12.  override def demo() {  
  13.   println("LineElement's implementation invoked")  
  14.  }  
  15. }  
  16. // UniformElement inherits Element’s demo  
  17. class UniformElement extends Element  
如果你把这些代码输入到了解释器中,那么你就能定义这个带了一个Element并调用demo的方法:

  1. def invokeDemo(e: Element) {  
  2.  e.demo()  
  3. }  
如果你传给invokeDemo一个ArrayElement,你会看到一条消息指明ArrayElement的demo实现被调用,尽管被调用demo的变量e的类型是Element:

  1. scala> invokeDemo(new ArrayElement)  
  2. ArrayElement's implementation invoked  
相同的,如果你传递LineElement给invokeDemo,你会看到一条指明LineElement的demo实现被调用的消息:

  1. scala> invokeDemo(new LineElement)  
  2. LineElement's implementation invoked  
传递UniformElement时的行为一眼看上去会有些可以,但是正确:

  1. scala> invokeDemo(new UniformElement)  
  2. Element's implementation invoked  

因为UniformElement没有重载demo,它从它的超类Element继承了demo的实现。因此,当对象的类是UniformElement时,Element的实现就是要调用的demo的正确实现。

【相关阅读】

  1. Scala学习:调用超类构造器和override修饰符的使用
  2. Scala:重载方法和字段及定义参数化字段
  3. Scala程序中的扩展类
  4. 在Scala中定义无参数方法
  5. 学习Scala的二维布局库和抽象类

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...