概要
愛しさと切なさと某かと。
Groovyでオーバロードってできるよね?という確認です。
あれ、じゃあダックタイピングは?あれ?型があると。。。?とちょっと混乱したのでメモ。
#オーバロード
普通です。すごく普通です。Javaと同じです。
メソッド名が同じでも、引数の型、引数の個数が異なれば、同じクラス内で同名メソッドを宣言できるのがオーバロードです。
class Value {/*Test用クラス*/}
class Hoge {
def test(String a) {
"This is String"
}
def test(Integer a) {
"This is Integer"
}
def test(Value a) {
"This is Value Object"
}
}
def obj = new Hoge()
assert obj.test(111) == "This is Integer"
assert obj.test("a") == "This is String"
assert obj.test(new Value()) == "This is Value Object"
#Groovyの引数の型について
Groovyは変数を def で宣言して、変数の型を省略できます。
しかし、その場合は Object型 として扱われるので、上記のソースのメソッド引数から、型を省略するとエラーになります。(The method public java.lang.Object test(java.lang.Object a) { ... } duplicates another method of the same signaturetというエラーメッセージ)
class Hoge {
// def test(Object a)と同意
def test(a) {
"This is String"
}
// 結果的に、"def test(Object a)" と同じなので、すでに上で宣言されているものと被る。
def test(a) {
"This is Integer"
}
// 結果的に、"def test(Object a)" と同じなので、すでに上で宣言されているものと被る。
def test(a) {
"This is Value Object"
}
}
わざわざ変数の型を宣言しなくても良いというのはスクリプトライクにサクサクコードを書くのに非常に便利な機能ですが、Groovyの場合、すでに上述していますが、その場合には Object型 として扱われるため、オーバロードが利用できません。
メソッド、クロージャの引数に型を宣言しておくと、態々渡された値のチェックをする必要がなくなります。(当然あくまで型ベース。限界値チェックとかそこのあたりは別の話)
#ダックタイピングのサンプル
引数に型を宣言するとダックタイピングできなくなっちゃうじゃん。。。
ということで、ダックタイピングしたい場合には型を省略する必要があります。
ダックタイピングとは、メソッドを呼ばれるオブジェクトが異なるクラスであったとしても、同じメソッド名とか持ってれば実行できるから良いんだよ!というものです。
(ここでいう 異なるクラス とは 継承関係のないクラス の事です。)
class Value1{ def test() {"This is Value1 Object"}}
class Value2{ def test() {"This is Value2 Object"}}
class Hoge2 {
def test(a) {
a.test()
}
}
def obj2 = new Hoge2()
assert obj2.test(new Value1()) == "This is Value1 Object"
assert obj2.test(new Value2()) == "This is Value2 Object"
#その他
ちなみにScalaの場合は型宣言せずとも、型推論されてちゃんと対応する型の変数になりますが、Groovyだと無条件にObject型になります。
ここだけ切り取ると、デフォルトでオーバロードできるScalaのほうが、デフォルトでオーバロードできずにダックタイピングはできるGroovyよりもJavaに近いな〜という印象を受けました。(あくまでここだけ)
(Scalaでもダックタイピングはできて更に必要なメソッドも要求できるので、より安全です。)
Groovyの型に関しては以前ブログにも書いていますので、そちらもどうぞ。
Groovyでメソッドの引数に型を指定する意味