Scala中不同的重写方法有什么区别?

时间:2012-09-01 21:25:06

标签: scala override

Scala允许您以两种合法方式覆盖方法:

鉴于超级课程:

class A {
  def a = "A"
}

我们可以通过以下方式覆盖方法“a”:

class B extends A {
  override def a = "B"
}

class B extends A {
  override def a() = "B"
}

两者似乎都正确地覆盖了方法“a”。这背后的设计决策是什么?为什么允许B中的“a()”覆盖A?

中的“a”

1 个答案:

答案 0 :(得分:15)

情况并非总是如此(来自the language specification的更改日志):

  

Scala 2.0版也放宽了覆盖规则   空参数列表。 匹配成员的修订定义   (§5.1.3)使得现在可以使用显式覆盖方法,   但是使用无参数方法的空参数列表()版   反之亦然

你是正确的,这似乎是一个奇怪的设计决定,因为无参数方法和具有空参数列表的方法之间存在可观察到的差异。例如,假设您有以下内容:

class A { def a = "A" }
class B extends A { override def a = "B" }
class C extends A { override def a() = "C" }

现在我们可以按预期编写以下内容:

scala> (new B).a
res0: java.lang.String = B

scala> (new C).a
res1: java.lang.String = C

而且:

scala> (new C).a()
res2: java.lang.String = C

但不是这样:

scala> (new B).a()
<console>:10: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
Unspecified value parameter index.
              (new B).a()

因此Scala确实区分了两者,这显然必须反映在字节码中。假设我们编译以下内容:

class A { def a = "A" }
class B extends A { override def a = "B" }

然后运行:

javap -verbose B > noArgList.txt

然后将代码更改为:

class A { def a = "A" }
class B extends A { override def a() = "B" }

重新编译,然后运行:

javap -verbose B > emptyArgList.txt

最后检查差异:

<   MD5 checksum 88aeebf57b645fce2b2fcd2f81acdbbd
---
>   MD5 checksum 3733b3e4181b4b2f4993503d4c05770e
32c32
<   #18 = Utf8               }1A!
                                 \t\t!ICaT-9uszaE\r)\"a\tI!!\"1Q!Dg
jiz\"a\tAQ!BY\t!Y                                                  G.Y11bU2bY|%M[3di\")C%1A(
                 /A$H3)!dGYtwMCQM^1\nyI\"AB*ue&tw\r
---
>   #18 = Utf8               }1A!
                                 \t\t!ICaT-9uszaE\r)\"a\tI!!\"1Q!Dg
jiz\"a\tAQ!BY\t!                                                   G.Y11bU2bY|%M[3di\")C%1A(
                /A$H3)!dGYtwMCQM^1\nyI\"AB*ue&tw\r

因此存在差异 - 两个版本对ScalaSignature注释具有不同的值。

至于为什么在Scala 2.0中进行了更改:规范指出它允许这样做:

class C {
    override def toString: String = ...
}

我的猜测是语言设计人员没有理由要求用户记住在这种情况下使用被覆盖方法的方法。