Scala中不同的覆盖方法之间有什么区别? [英] What is the difference between the different overriding methods in Scala?

查看:57
本文介绍了Scala中不同的覆盖方法之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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"?

解决方案

情况并非总是如此(来自

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

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 = ...
}

我的猜测是,语言设计师只是没有理由要求用户记住在这种情况下所使用的重写方法.

Scala lets you override a method in two legal ways:

Given super class:

class A {
  def a = "A"
}

We can override the method "a" by:

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?

解决方案

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.

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:

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 ScalaSignature annotation.

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

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.

这篇关于Scala中不同的覆盖方法之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆