2013-02-14 7 views
7

テンプレートクラスに関連していないコレクションがそのタイプを削除するのはなぜですか?ここでは一例である:(。申し訳ありませんが、それはので、私は混乱していエラーがコンパイルされません)一般的なネジアップ関連以外のコレクション

package test; 

import java.util.ArrayList; 
import java.util.List; 

public class TemplateTest { 

    public static class A { } 

    public static class B<T extends Comparable> { 
     List<A> aList = new ArrayList<A>(); 

     public List<A> getAList() { 
      return aList; 
     } 

     public int compare(T t, T t1) { 
      return t.compareTo(t1); 
     } 
    } 

    public static void main(String[] args) { 
     B b = new B(); 
     for (A a : b.getAList()) { //THIS DOES NOT WORK 

     } 
     List<A> aList = b.getAList(); //THIS WORKS 
     for (A a : aList) { 

     } 
    } 
} 

このコードはコンパイル時にエラーがスローされます:

test/TemplateTest.java:24: incompatible types 
    found : java.lang.Object 
    required: test.TemplateTest.A 
     for (A a : b.getAList()) { 

私はテンプレートを指定した場合BのようにB<String>、またはテンプレートをBから完全に削除した場合はすべて正常です。

何が起こっているのですか?

編集:それはC++であるような人々は、私は

+1

前ナンセンスについては申し訳ありませんバグに関連している。名誉! –

+1

あなたの質問に厳密には関係しませんが、Javaではtypeパラメータを指定しない*は*一般にプログラミングエラーとみなされます。生の型を使用することは、下位互換性のための譲歩としてのみコンパイルします。 – Affe

+0

私はコンパイラのバグも呼び出します。拡張されたforループで使用される右側の式の型が特殊な方法で決定され(特殊な配列を必要とするので驚くことではない)、生の型が含まれている場合はこれが中断されるようです。 (私は生の型をどこかで見ると、式全体が型が消去されていることを前提としています)。 – millimoose

答えて

8

はい、その後、あなたは生のタイプを使用する場合ことが知られて動作です宣言に失敗した型レベルのパラメータだけでなく、クラスのすべての型パラメータが失われます。

私はB<String>のようにBのテンプレートを指定した場合、または私は完全にBから テンプレートを削除する場合は、すべてがOKです:

問題の一部がここにあります。

これはオプションではありません。タイプパラメータを指定するかどうかを選択する必要はありません。パラメータを指定せずにコンパイルする唯一の理由は、下位互換性のためです。タイプパラメータがない新しいコードを書くことはプログラミングエラーです。

List<A> list = b.getList()は、タイプを正常に解釈しません。これは、任意のキャストを効果的に使用し、割り当てが正しいことを信頼しています。コンパイラの警告を見ると、実際には安全でない変換の警告が生成されています。

for(A a : b.getList()) {}警告は、挿入されたキャストがコンパイラによって生成されたコード内にあるため警告が表示されるため、警告を出すのではなく、安全でないコードを自動生成することを拒否します。生タイプの使用が唯一のレガシーコードの互換性 への譲歩として許可されている

:Java言語仕様から

。 のJavaプログラミング言語への一般性の導入の後に書かれたコードでの生の型の使用は、 が強く推奨されていません。 Java プログラミング言語の将来のバージョンでは、生の型の使用を禁止する可能性があります。

ボトムラインは本当にC++テンプレートとだけ重要なもののJavaのジェネリック医薬品のシェアは<>構文:)

詳細であるということである。これは、ように見える... What is a raw type and why shouldn't we use it?

+0

しかし、Sunはhttp://stackoverflow.com/a/14882182/688653で述べたバグを受け入れています。これはバグか正しい振る舞いですか? –

+0

これは、式の型が拡張されたfor-loopのコンテキストの* outside *であると決まった理由を説明していません。 – millimoose

+0

@millimoose私はそれが正しく外部に決定されたとは思わないが、私はエラーの代わりに警告を得る。例えば ​​'List list = notDeclared.getAList();'は私に「チェックされていない変換」警告を与えます。 – sharakan

1

まずBに追加Bは、ジェネリックにする必要はありませんでした指摘し、Javaで、それがないテンプレート、ジェネリックです。

クラスBに汎用タイプのパラメータTを宣言していますが、使用していません。 Bクラス定義ではAの代わりにTを使用する必要があります。

public static class B<T> { 
    List<T> aList = new ArrayList<T>(); 

    public List<T> getAList() { 
     return aList; 
    } 
} 

あなたはクラスBのインスタンスを宣言するとき、あなたは型パラメータを使用する必要があります。

B<A> b = new B<A>(); 

しかし、あなたはメソッド名getAListが示すように、あなたのaList変数は常にタイプAのオブジェクトを保持することがわかっている場合、そのクラスBがジェネリックにする理由はないだろう。

+0

Tを別の場所で使うことはできますが、Tを指定しなければAをねじ込みます。 – naugler

+0

クラスBのジェネリック型パラメータを指定することは、その "getAList"メソッドが特定の型 "T"のリストを返すことを意味しますが、まだどの型であるのかは気にしません。 「T」のタイプは、インスタンスが作成されるまで指定されません。インスタンス "b"を "B"型で作成する場合は、型パラメータ "A"を指定します。 "getAList"を呼び出すと、リストが返されます。 – rgettman

+0

いいえ、リストをタイプAにします。タイプTは他の場所で使用されます。なぜ私のAオブジェクトのリストが型を落とすのですか? (私はTの可能な使用を示すために私の例を追加しました、ごめん、それは粗いです) – naugler

1

これは、このバグには本当に似ています

ここで報告され

6760983 : Unused type parameter triggering error in unrelated method

Unused Generic causing problem

+0

しかしOPのコードはサブクラス化されていないので、バグが示唆するようにオーバーライドや名前の衝突はありません。 – splungebob

+0

真実ですが、そのバグでは、追加の型パラメータがコンパイラを混乱させ、2つの(明らかに)一致する型の型チェックが失敗するようにコンパイラを混乱させました。多分彼らは関連しているでしょうか?別の考え:多分Javaの別の実装がここで助けることができますか? –

+0

@ ZiyaoWei Sunの代わりにEclipseコンパイラを試すことができます。 – millimoose

関連する問題