2016-07-01 7 views
8

私はこのような簡単なプログラムがあります:あなたはそれは絶対に何もしません見ることができるようにJavaのジェネリック - 汎用的な機能を持つジェネリッククラスを拡張

package test; 

public class TestGenericsInheritance { 

    public static void main(String[] args) {} 

    public static abstract class A<Q>{ 

     public void foo2(Q obj){} 
     public abstract <T> void foo(T obj); 
    } 

    public static class C extends A<Object>{ 

     @Override 
     public <T> void foo(T obj) {} 
    } 

    public static class B extends A{ 

     @Override 
     public <T> void foo(T obj) {} 
    } 
} 

を。次のエラーでJava 1.6および1.7でこのプログラムファイルの編集:

/D:/Projects/.../test/TestGenericsInheritance.java:[24,19] test.TestGenericsInheritance.B is not abstract and do es not override abstract method foo(java.lang.Object) in test.TestGenericsInheritance.A /D:/Projects/.../test/TestGenericsInheritance.java:[27,25] name clash: foo(T) in test.TestGenericsInheritance .B and foo(T) in test.TestGenericsInheritance.A have the same erasure, yet neither overrides the other /D:/Projects/.../test/TestGenericsInheritance.java:[26,9] method does not override or implement a method from a supertype

クラスCとBは、しかし、クラスBは、#fooの実装としてメソッドfooを認識しない、意味的に同じです。このコードを作るために準拠した私は、メソッドに次のシグネチャを持つクラスBに#FOOを実装する必要があります。

public void foo(Object obj) 

私のプログラムがコンパイルできない理由私の質問は、ありますか?ジェネリック型QとTは完全に独立しているので、ジェネリック関数A#fooは、継承クラスAのジェネリック型Qを明示的に指定した場合にのみ実装できます。

おかげ

+0

私はrepro 'することができます。さらに、非ジェネリックメソッドとジェネリックメソッドを同時に持つと、同じタイプのイレージャを持つエラーが発生します。 – 4castle

+0

Eclipseは、 '' '@Override public void foo(Object obj){}' 'を' '' B'''に追加することを提案しています。 (1.8) –

+0

@ 4castleあなたが編集したファイルでは、削除したソースファイル名にエラーメッセージが混乱します。 –

答えて

6

Bは、生タイプAを拡張します。生の型を使用するため、指定しなかった型変数(Section 4.6 of the Java Language Specification参照)だけでなく、すべての汎用情報が消去されます。これは、Aが方法void foo(Object obj)を有し、A<SomeType>が方法<T> void foo(T obj)を有することを意味する。

メソッドをオーバーライドする場合は、同じシグネチャ(必要に応じてオーバーライドされたメソッドの型を削除した後)を持たなければなりません - 興味深いことに、オーバーライドするメソッドは異なる、より具体的な戻り型を持つ可能性があります。あなたの2つのメソッドのシグネチャは異なります(オーバーライドするメソッドで型を削除する必要があります)ので、サンプルはコンパイルされません。

理由タイプの消去がそのまま実装されていたのは下位互換です。新しいコードではジェネリックのみを使用し、古いコードでは生のタイプを使用するという考えがありました。だから、生の型をもっとも便利にすることは目的ではありませんでした。なぜなら、新しいコードでは使用しないでください。

たとえば、Java 2で導入されたクラスArrayList(一般には一般的なもの)を考えてみましょう。それは方法public Object[] toArray(Object[] a)を持っていた。 Java 5ではジェネリックが導入され、このメソッドのシグネチャはpublic <T> T[] toArray(T[] a)Tは要素タイプではありません)に変更することができます。方法のタイプの消去が実装されているため、むしろArrayListを使用した(またはサブクラス化した)古いコードArrayList<SomeType>よりメソッドシグネチャは同じままです。

+0

私はまだそれを取得しません。 「すべての一般情報が消去されています」はどこに表示されますか? – 4castle

+1

それは言います: "タイプ消去はまた、コンストラクタまたはメソッドのシグネチャ(8.4.2)を、パラメータ化された型または型変数を持たないシグネチャにマッピングします。"そこに追加の条件の言及はありません。 – Hoopje

+0

@Hoopjeあなたの説明をありがとう。私は私の問題の背後にある理由は何かを理解しています。しかし、私はそのような場合にはすべてのジェネリック型を消去することに何の意味も見ません。私は型パラメータを消去する必要があることを理解しています。しかし、それは型パラメータから独立している場合、なぜメソッドのパラメータを消去するのですか?そのような消去が必要な場合は何でもご提供いただけますか? – MAREK

関連する問題