ジェネリック型の配列の作成/コピー

私はかなりの胃痛を与えるジェネリック薬に関する問題を解決しなければならない。

基本的には、配列ベースの最大ヒープの実装であると考えられており、与えられた条件に従わなければなりません。 このコードは次のようになります。

//Interface with methods such as insert(), remove(), etc
public interface IMaxHeap> {
   ...
}

public class MaxHeap> implements IMaxHeap{
    T[] m_array;

    ...

    public MaxHeap(int size){
        //TODO:
        //m_array = new T[size];
    }
    public MaxHeap(T[] array){
        //TODO:
        //Deep copy of array into m_array
    }
}

2つのコンストラクタのコードは、私が驚いているものです。 私はメソッドのシグネチャを変更するようにはなっていないので、このようなことはできません:

public MaxHeap(Class clazz, int size){
    m_array = (T[]) Array.newInstance(clazz, size);
}

さらに、このようなObject []配列の「安全でない」型キャストを実行すると、実行時の威力(InvocationTargetException)が発生し、

public MaxHeap(Class clazz, int size){
    m_array = (T[]) new Object[size];
}

私は配列のコピーを作成する一般的な方法を見つけましたが、それはディープコピーではありません:

public MaxHeap(T[] array){
    m_array = Arrays.copyOf(array, array.length);
}

だから、この点m_array [0] == array [0]は私が探しているものではない。

また、クラスに他の制約を追加することも想定していません( T Exdends Cloneable もありません)。これらの問題を考えると、実際に配列をインスタンス化する方法は見つけられませんでした。

私は幾分ジェネリックス(私はC + +のテンプレートで作業してきた)の新しいですので、Tのそれらの癖はかなり迷惑です。 皆さんは私に問題の解決策を教えてもらえますか?

1
私は配列を「深くコピーする」ことが何を意味するのか見当たりませんか?
追加された 著者 fge,
ああ、なるほど。 .clone()を使用することができます。
追加された 著者 fge,
@fge - 浅いコピーは新しい配列を作成しますが、同じオブジェクトへの参照をその配列に置きます。つまり、 a [0] == b [0] を意味します。深いコピーは各オブジェクトを複製し、 a [0]!= b [0] ではなく a [0] .compareTo(b [0])== 0
追加された 著者 s3rius,
クローン()は保護されており、Tのために上書きされなければならないので、@ fge - これは不可能です。
追加された 著者 s3rius,

2 答え

私の経験からすれば、バッキング配列を Object [] 型にし、その要素を読むときに T 型にキャストするのが標準的な方法です。

一般に、Javaでジェネリック型の配列を扱うのは、本当に危険で紛らわしいものです。できるだけ避けるのが最善です。

しかし、あなたがこのようにすることを主張するとき、これは解決策であるようです。

    public MaxHeap(int size){
        m_array = (T[])new Comparable[size];
    }
    public MaxHeap(T[] array){
        this(array.length);
        System.arraycopy(array, 0, m_array, 0, array.length);
    }
2
追加された
@ s3rius宿題の場合は、それをタグ付けする必要があります;)また、配列を使用することしていますか?あなたは、ArrayListsを使用することはできませんか?
追加された 著者 fge,
彼らは Object [] の代わりに T [] を使用すると明示的には言及していませんが、この練習では示唆されています。だから私はそれを試してみたいと思います。
追加された 著者 s3rius,
@fge - 私はそれをretagするでしょう。残念ながら、私は通常の配列を使用する必要があります。
追加された 著者 s3rius,
@Nayuki - それは array がディープコピーではないという問題を残します。しかし、少なくとも正しい方向への一歩です!
追加された 著者 s3rius,
@NayukiMinase - 1つのレベル。だから私は配列の中で直接参照されているオブジェクトのクローンが必要です。
追加された 著者 s3rius,
どのくらい深いコピーが必要ですか?
追加された 著者 Nayuki,
arraycopy()の呼び出しを次のように置き換えてみてください: for(int i = 0; i
追加された 著者 Nayuki,

Even with Java generics and type erasure, as your class implements IMaxHeap, you can get T.class at runtime using reflection, and at that point everything becomes easier. The following should work:

  1. Call Class.getGenericInterfaces() to get the interfaces implemented by your class, with generic type information. The first result should be a Type instance representing IMaxHeap.
  2. Cast that to a ParameterizedType.
  3. Call ParameterizedType.getActualTypeArguments() on that. You will get a Type representing T.
  4. Cast that to Class.

基本的に、Javaでは、特定のジェネリッククラスの実際の型引数を取得することはできませんが、そのスーパークラスとインタフェースの実際の型引数を取得できます。問題は、実行時にこれらの実際の型を知る必要があるため、ランタイムチェック/キャストを適切に行うことができることです。

1
追加された
一般的に、 Type インスタンスは Class である必要はありません。実際、 MaxHeap のサブクラスを使用しない限り、 TypeVariable になります。取り消しの取り消しはそれよりも複雑です(呼び出し元が適切なクラスオブジェクトを提供していなければ、必ずしも可能ではありません)。
追加された 著者 meriton,
@meritonおっと、あなたは正しいです!
追加された 著者 gpeche,