2017-05-27 13 views
2

キャスト:==>Exception [Object cannot be cast to [clTag ????ジェネリック配列は、一般的な配列を返すメソッドで、私はこのジェネリッククラスを持っている例外

誰でも私の理由を説明できますか?

私はこれの多くを同じように適用することはできません。How to create a generic array 私は醜い回避策を持っている:

return Arrays.asList(txtTags.getItems()).toArray(new clTag[0]) 

をしかし、私は、その後ZTagFieldClassでそれを持ってしたいと思います。

+0

スタックトレースを投稿してください。 – Turing85

+0

すべての良い3つのアプローチ。配列の代わりにListを返す方がはるかに簡単なので、まず設計に戻り、リストの代わりに配列を返すようにこのクラスを設計した理由を見てみましょう。ありがとう。 – lvr123

答えて

3

動作時:実行時にジェネリック型はありません。

消去され、Objectの配列が作成されます。 Objectの配列を別の種類の配列にキャストすることはできません。

これは、Javaジェネリックの制限事項の1つで、実装方法に基づいています。

これは、ジェネリックと一緒に配列を使うことに注意することをお勧めします。代わりにジェネリックリストを使用することをお勧めします。

これについてはっきりしています:はい、ジェネリックで動作するように、他の回答でもエレガントに表示されます。しかし、あなたはあなたの時間を費やして、そのような症状を抑えます。配列とジェネリックはJavaでうまくいっていません。それを受け入れる、一般的なリストを使用し、それゆえ:それを回避するのではなく、問題を修正する。

+0

短く効果的です。それはしばしば十分です:) – davidxxx

+0

ありがとうございます。私はあなたの評価に同意します。他の答えは啓発です! – GhostCat

+0

Objectの配列が作成されるという事実は、消去またはジェネリックスとは関係ありませんが、彼が渡したものに基づいて呼び出しているメソッドのランタイムセマンティクスにしか書かれていません。 – newacct

4

アレイが改訂されました。つまり、コンポーネントタイプへの参照を保持し、要素を挿入するときには、その参照を使用して、挿入された要素が実際にコンポーネントタイプのサブタイプであるかどうかを確認します。このため

は、T[]を作成するには、コンポーネントタイプTへの具体的な言及を必要とし、ジェネリック医薬品が消去されているので、ジェネリックTはカウントされません。 (それはあなたがまっすぐにT[]T[] arr = new T[]などを作成することができない理由でもあります。)

コレクションのtoArray方法は、ユーザーがコンポーネント型の配列を渡すことによってこの問題を回避取得します。しかし、を試すこれはあなたのObject[]T[]にキャストして実際にTの配列を作成しないでください(Tの由来は?)。このようなキャストは、Tが実際にObjectでない限り、チェックされていないと失敗します。

また、ClassCastExceptionが由来しています。 Object[]を作成すると、T[]にキャストしてもコンポーネントタイプはObjectであり、コンポーネントタイプはObjectのままです。

public clTag[] getSelectedTags() { 
    return (clTag[]) txtTags.getItems(); 
} 

しかし、あなたがObject[]をキャストすることはできません。

public clTag[] getSelectedTags() { 
    return txtTags.getItems(); 
} 

だからコンパイラはclTag[]に、ここでの暗黙的なキャストを挿入します。しかし後に、あなたがしたい、実際のコンポーネントタイプ(clTagを)知っていますclTag[]と同じようにObjectclTagにキャストできないようです。

あなたの問題を回避するには、あなたが実際にコンポーネント型への参照を供給しているので、動作します、コンポーネント型の配列を渡すよりも、より近代的な解決策はIntFuntion<T[]>を渡すことです

Arrays.asList(txtTags.getItems()).toArray(new clTag[0]) // <-- 'clTag' here 

メソッドに、配列コンストラクタをカプセル化:...

public T[] getItems(IntFunction<T[]> arrCons) { 
    ... 
    T[] arrItems = currentItems.toArray(arrCons.apply(0)); 
    return arrItems; 
} 

txtTags.getItems(clTag[]::new); 

しかし、List<T>(GhostCatも示唆したとおり)を返すように切り替えない限り、何らかの方法でコンポーネントタイプを渡す必要はありません。ジェネリック医薬品はが具体化されていないので、あなたがコンポーネントタイプを参照することなくList<T>を作成することができますコンパイルした後

public List<T> getItems() { 
    ... 
    return new ArrayList<>(currentItems); 
} 
2

、タイプが消去されます。
Tは特定のタイプに限定されていないため、TObjectに置き換えられます。

ので、この:

T[] arrItems = (T[]) currentItems.toArray((T[])...); 
return arrItems; 

は作成して、実行時にクラスのインスタンスで使用される特定の型の配列を返すだけObjectの配列を作成しますしません。

また、Collection.toArray()にあなたは一般的な配列を作成することが有効ではありませんためのアレイ(new T[])のいずれかを渡すことはできません。あなたがtoArray()メソッドを使用したい場合は

したがって、あなたは最終的にのみ、この方法でObjectの配列を渡すことができます。

Object[] arrayObject = values.toArray(new Object[currentItems.size()]); 

しかし、配列はリスト型としては機能しません。
特定の型の配列は、その中に含まれる要素の型がキャストの対象の型であっても、別の型の配列にキャストできません。
したがって、Objectの配列を、特定の型の配列にキャストすることはできません。

だから、これはClassCastExceptionが生成されます:あなたの問題を解決するために

clTag[] values = (clTag[]) arrayObject; 

を:


は、Java 8を使用することができた場合は、機能インタフェースを使用すると、本当にきれいなソリューションです。 ジョーン・バーニーはそれを説明する非常に良い答えを与えました。

1)指定された型で新しい配列を作成します。Java 8、ジェネリックコレクションで使用されるパラメータ化された型であることを、同じタイプの配列を作成するための単一の方法は、前

それ以外の場合は、。
java.lang.reflect.Array.newInstance(Class clazz, int length)メソッド では、指定されたクラスと長さの配列を作成できます。

2)宣言された型のクラスを汎用クラスのインスタンスに格納する。クラスのコンストラクタにクラスパラメータを追加することでそれを行うことができます。

3)ジェネリックコレクションの要素からデータを取り込みます。
簡単な方法は<Object, Object> Object[] java.util.Arrays.copyOf(Object[] original, int newLength, Class<? extends Object[]> newType)メソッドを使用していますが、最初にtoArray()の配列にコレクションを変換してcopyOf()メソッドに渡す必要があるため、効果的ではありません。

は、一般的なListとたとえば、次のように書くことができます:それは効果的ではないと述べて

public class ZTagField<T> { 

    private class<T> clazz; 
    private List<T> list = new ArrayList<>(); 

    public ZTagField (class<T> clazz){ 
     this.clazz = clazz; 
    } 

    public T[] get() {  
     T[] array = (T[]) Array.newInstance(clazz, list.size());    
     Class<? extends Object[]> clazzArray = array.getClass(); 
     array = (T[]) Arrays.copyOf(values.toArray(), values.size(), clazzArray); 
     return array; 
    } 
} 

それはしかし、動作します。
より効果的な解決策は、リスト上で反復し、代わりにArrays.copyOf()を使用しての新しい配列に要素を追加することになります。

public T[] get() {  
     T[] array = (T[]) Array.newInstance(clazz, list.size());    
     for (int i = 0; i < values.size(); i++) { 
      array[i] = values.get(i); 
     } 
     return array; 
    } 
+0

これもまた啓発されます。 – GhostCat

+0

問題ありません。あなたは私の答えをさらに高めるために私にインスピレーションを与えました。さて、オペアンプが何を言いたいのか見てみましょう。もし彼が戻ってきた場合:-) – GhostCat

+1

答えを改善することは常に良いことです:)待ってください。確かに:3つの答えが異なり、本当に問題の異なる側面を扱います: 8道。 – davidxxx

関連する問題