同じクラスに次の 2 つのメソッドが存在するのはなぜ不正なのでしょうか?
class Test{
void add(Set<Integer> ii){}
void add(Set<String> ss){}
}
私はcompilation error
メソッド add(Set) には、型 Test の別のメソッドと同じ消去 add(Set) があります。
回避策はありますが、javac がなぜこれを好まないのか疑問に思いました。
多くの場合、これら2つの方法のロジックは非常に似ており、1つの方法に置き換えることができることがわかります。
public void add(Set<?> set){}
方法ですが、常にそうであるとは限りません。
constructors
これらの引数を取る を 2 つ用意したい場合、そのうちの 1 つの名前を変更するだけでは不十分なため、これはさらに面倒ですconstructors
。
ベストアンサー1
このルールは、生の型をまだ使用しているレガシー コードでの競合を回避することを目的としています。
これがなぜ許可されなかったのか、以下に例を挙げて説明します。JLS から抽出されました。ジェネリックが Java に導入される前に、次のようなコードを書いたとします。
class CollectionConverter {
List toList(Collection c) {...}
}
次のようにクラスを拡張します。
class Overrider extends CollectionConverter{
List toList(Collection c) {...}
}
ジェネリックの導入後、ライブラリを更新することにしました。
class CollectionConverter {
<T> List<T> toList(Collection<T> c) {...}
}
更新する準備ができていないので、Overrider
クラスはそのままにしておきます。メソッドを正しくオーバーライドするためにtoList()
、言語設計者は、生の型がジェネリック型と「オーバーライド同等」であると判断しました。つまり、メソッド シグネチャはもはやスーパークラスのシグネチャと形式的には等しくありませんが、メソッドは依然としてオーバーライドします。
さて、時間が経ち、クラスを更新する準備ができたと判断しました。しかし、少し失敗してしまい、既存の未加工のtoList()
メソッドを編集する代わりに、次のような新しいメソッドを追加してしまいました。
class Overrider extends CollectionConverter {
@Override
List toList(Collection c) {...}
@Override
<T> List<T> toList(Collection<T> c) {...}
}
生の型のオーバーライド同等性のため、両方のメソッドはメソッドをオーバーライドする有効な形式になっていますtoList(Collection<T>)
。ただし、もちろん、コンパイラは単一のメソッドを解決する必要があります。このあいまいさを排除するために、クラスにはオーバーライド同等の複数のメソッド、つまり消去後に同じパラメーター型を持つ複数のメソッドを含めることはできません。
重要なのは、これが生の型を使用する古いコードとの互換性を維持するために設計された言語ルールであるということです。これは、型パラメータの消去に必要な制限ではありません。メソッドの解決はコンパイル時に行われるため、メソッド識別子にジェネリック型を追加するだけで十分でした。