Scala 中不同的覆盖方法有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12231534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:29:42  来源:igfitidea点击:

What is the difference between the different overriding methods in Scala?

scalaoverriding

提问by platypus

Scala lets you override a method in two legal ways:

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

Given super class:

给定超类:

class A {
  def a = "A"
}

We can override the method "a" by:

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

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

and

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

both seem to override the method "a" correctly. What is the design decision behind this? Why allow for "a()" in B to override "a" in A?

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

回答by Travis Brown

This hasn't always been the case (from the change log of the language specification):

情况并非总是如此(来自语言规范的更改日志):

Scala version 2.0 also relaxes the rules of overriding with respect to empty parameter lists. The revised definition of matching members(§5.1.3) makes it now possible to override a method with an explicit, but empty parameter list ()with a parameterless method, and vice versa.

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

You are correct that this seems like an odd design decision, given that there are observable differences between parameterless methods and ones with empty parameter lists. For example, suppose you have the following:

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

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

Now we can write the following, as expected:

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

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

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

And this:

还有这个:

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

But not this:

但不是这个:

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()

So Scala does make a distinction between the two, which obviously must be reflected in the bytecode. Suppose we compile the following:

所以Scala确实对两者做了区分,这显然必须体现在字节码上。假设我们编译如下:

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

And then run:

然后运行:

javap -verbose B > noArgList.txt

Then change the code to this:

然后把代码改成这样:

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

Recompile, and run:

重新编译,运行:

javap -verbose B > emptyArgList.txt

And finally check for differences:

最后检查差异:

<   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

So there is a difference—the two versions have different values for the ScalaSignatureannotation.

所以是有区别的——两个版本的ScalaSignature注释值不同。

As to whythe change was made in Scala 2.0: the specification notes that it allows this:

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

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

My guess is that the language designers just didn't see a reason to require users to remember which approach the overridden methods used in cases like this.

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