ここでは次の 2 つのことが行われています。
- 関数とメソッドは同じものではありません
- メソッドは、パラメーターの型が多態的ではありません
あなたのtester
メソッドはメソッドではなく、Function1
. アンダースコア構文を使用して、関数に持ち上げることができます。
val f = (new FooTest[String]).tester _ // Fasel => Bla
この関数は、その入力型が反変になります。(ただし、関数はパラメーター化できないことは言うまでもありません。また、メソッドの関数オブジェクトを取得するには、Foo
またはのインスタンスが必要であると言う価値もあります。これはもちろん、最初の観察から導かれます!)FooTest
tester
関数はオブジェクトであり、意味がないためオーバーライドできません。メソッドはオーバーライドできます。ただし、上で述べたように、オーバーライドはメソッドのパラメーター型では多態的ではありません。たとえば、次のようになります。
class A {
def foo(a : Any) = println("A: " + a)
}
class B extends A {
override def foo(s : String) = println("B " + s) //will not compile!
}
上記の例の 2 つのメソッドは、2 つの別個のメソッドです。動的ディスパッチは、メソッド ターゲット (つまり、呼び出されているオブジェクト) でのみ機能します。
上記の例では、宣言を削除するoverride
と、コードはコンパイルされます。以下を実行する場合:
(new B).foo(1) //prints A 1
(new B).foo("s") //prints B s
これは、両方のメソッドが呼び出されfoo
ていますが、完全に異なるメソッドであるためです (つまり、オーバーロード foo
したのではなく、オーバーライドしたためです)。メソッドの引数 (それらの型を含む) は、そのメソッドの一意の名前の一部を形成するということとして最もよく理解されています。名前がまったく同じ場合にのみ、1 つのメソッドが別のメソッドをオーバーライドします。
基本的に、あなたは質問で2つの別々の関連のないものを混同しています。明確にするためにそれらを下に置きます。
- 上のバリアンス アノテーション
Function1
は、ある関数が別の関数のサブタイプである (したがって、特定の型の参照に割り当て可能である) ことの意味を定義します。
- メソッドはサブクラスでオーバーライドできます。言語仕様では、そのようなオーバーライドがいつ行われるかについてのルールが概説されています。