2012-02-20 23 views
11

のコンストラクタ呼び出しは、ジェネリック型

public class Pencil extends Item 
{ 
    public Pencil() 
    { 
     super(); 
    } 
    public Pencil(Integer value) 
    { 
     super(value); 
    } 
} 

を、なぜ私はできない私は理解していませんジェネリックを使用してコンストラクタを呼び出します。

public class Box <T extends Item> 
{ 
    T item; 
    public Box() 
    { 
     item=new T(); // here I get the error 
    } 
} 

コンストラクタを持たない型を持つことは可能ですが、 Pencilはパラメータを持たないコンストラクタを持ち、Itemは抽象型なので不可能です。 しかし、私は日食からこのエラーを受け取ります: はタイプTをinstanciateできませんT
私はなぜ、これを避ける方法がわかりません?

+0

あなたが持っている場合を考えてみましょうこのクラスを除いて 'Item'を拡張する別のクラス少なくとも1つの引数を主張するコンストラクタは1つしかありません。 –

+0

[Javaでジェネリック型をインスタンス化するにはどうすればいいですか?](http://stackoverflow.com/questions/6916346/how-can-i-instantiate-a-generic-type-in​​-java) –

+0

可能な複製[Javaでジェネリック型のインスタンスを作成する?](http://stackoverflow.com/questions/75175/create-instance-of-generic-type-in​​-java) –

答えて

9

Java型システムを使用して、クラス階層がそのサブクラスのコンストラクタに対して一様な署名を持つことを強制する方法はありません。

は考えてみましょう:

public class ColorPencil extends Pencil 
{ 
    private Color color; 

    public ColorPencil(Color color) 
    { 
     super(); 
     this.color=color; 
    } 
} 

これはColorPencil有効なT(それは項目を拡張する)ことができます。しかし、この型の引数なしコンストラクタはありません。したがって、T()は無意味である。

あなたが望むことをするには、リフレクションを使用する必要があります。コンパイル時エラーチェックの恩恵を受けることはできません。

11

Javaは、この参照、ジェネリックを実装するために消去を使用していますので、これは次のとおりです。

ジェネリック医薬品がチェックされます:ウィキペディア、上記の記事から関連部分を引用する

をコンパイル時に型の正確さのために。その後、型消去と呼ばれるプロセスで汎用型情報が削除されます。

タイプ消去の結果、実行時にタイプパラメータを特定できません。

したがって、インスタンス化ではコンストラクタの呼び出しが必要なため、パラメータ化された型のJavaクラスのインスタンス化は不可能です。型が不明な場合は使用できません。

実際にこのクラスを自分で提供することで回避できます。これはよくここで説明されています

+0

ありがとうございます。この回答はまさに私が探していたものでした。つまり、Javaのジェネリック実装の誤解と完全に一致しています。 :-) –

+0

@MichaelDorner確かに、助けてうれしい! –

0

実行時にTのタイプが不明であるため。

1

TあなたがBox<Item>をインスタンス化した場合、たとえば、その後Tが本当にItemのためだけの別名である、あなたのクラスが処理する実際の型の別名です。 T extends Itemを宣言すると、Tは少なくともItemと同じインターフェイスを持つことになるので、1つのように扱うことができます。

Boxitemフィールドをインスタンス化しないで、代わりにそのフィールドを操作できるように2つのメソッドを実装してください。

public class Box<T extends Item> { 
    private T item; 

    public T getItem() { 
     return this.item; 
    } 

    public void setItem(T item) { 
     return this.item = item; 
    } 
} 
0

コンパイルした後、あなたがこのようなコードを取得するよりも、それは可能であるかどうので、それはコンストラクタを呼び出すためにTを使用することは不可能です:

public class Box{ 
    Object item; 
    public Box(){ 
     item = new Object(); 
    } 
} 

ですから、このコードを使用して、いくつかのオブジェクトを渡す場合よりも、特定の型のコンストラクタが呼び出されると予想されますが、代わりにObjectコンストラクタを取得します。

+0

Javaのジェネリックがどのように実装されているかの詳細がわかりません – Alexander

0

抽象メソッドを配置して、実装クラスが新しいオブジェクトの作成方法を決定できるようにすることができます。

public abstract T constructT(); 

、代わりに

T t = new T() 

を呼び出すので、あなたのように、それが作成されます呼び出す実装に

T t = constructT(); 

を呼び出します。

new Box<Integer>() { 
    public Integer constructT(){ return new Integer(); } 
}