2011-02-06 11 views
1

intの固定サイズのバッファを作成する場合は、new int[size]を使用します。ここで、ジェネリック型にバッファを作成したいとします。Javaで固定サイズの汎用バッファを作成する方法は?

一つは、おそらく解決策は次のとおりです。

List<T> buffer = new ArrayList<T>(size); 
for (int i = 0; i < size; ++i) 
    buffer.add(null); 

// now simply access the buffer via buffer.get() and buffer.set() 

は、私が使うべきもっと良いものはありますか?サンプルユースケースはimplement a queueになります。これは実生活ではなくインタビューの質問です。

+0

あなたは正確に何をしようとしていますか? – Falmarri

+0

@Falmarri - 私は循環的なキューを実装しようとしており、基本的なデータストアとして構造体をバッファするのに使いたいと考えています。私は、固定サイズのバッファを割り当て、インデックスで要素にアクセスできるようにする必要があります。 – ripper234

+0

しかし、コンパイル時にわからない任意のオブジェクトを保持できるバッファが必要なのはなぜですか? – Falmarri

答えて

0

固定サイズのコレクションを制御できるカスタムクラス内に汎用コレクションをラップするだけです。たとえば、次のように

class Queue<T> { 
    private ArrayList<T> q; 
    private int size; 

    public Queue(int size) { 
     this.size = size; 
     this.q = new ArrayList<T>(size); 
    } 

    public int size() { 
     return size; 
    } 

    // ... 

    public T get(int index) { 
     if (index > q.size()) { 
      return null; 
     } 
     // ... or whatever 

     return q.get(index); 
    } 

} 

** EDIT **

以上具体的には、あなた自身のコレクションと互換性のある一般的なクラスを作成します。たとえば、次のようにこのテストされていないクラスはaddgetsetremove操作を許可しませんが、

public class FixedQueue<E> extends AbstractList<E> { 

    private Object[] queue; 

    public FixedQueue(int size) { 
     queue = new Object[size]; 
    } 

    @Override 
    public E set(int index, E element) { 
     Object old = queue[index]; 
     queue[index] = element; 
     modCount++; 
     return (E) old; 
    } 

    @Override 
    public E get(int index) { 
     return (E) queue[index]; 
    } 

    @Override 
    public int size() { 
     return queue.length; 
    } 

    @Override 
    public E remove(int index) { 
     Object old = queue[index]; 
     System.arraycopy(queue, index+1, queue, index, queue.length - index - 1); 
     modCount++; 
     return (E) old; 
    } 
} 

、などしかし、あなたがしたい場合は、あなたがあなた自身の仕様のためにそれを実装することができます。固定サイズの配列を使用する代わりにクラスを実装すると、他のソースに触れることなく実装するための機能(たとえばensureCapacity)を追加する必要がある場合に使用できます。私はちょうどあなたの編集を見た

** UPDATE **、基本的に、あなたは右のオフ始めています。要素を取得するときにジェネリック型にキャストする配列Objectを使用してください。たとえば、JavaのArrayList実装を参照してください。

+2

あなたの答えが私が質問で提供したコードサンプルとどのように違うのか分かりません。 – ripper234

+0

あなたの質問では、 'List'を直接使用しているように見えます。私は、リストを特定のクラスにラップして、一定数のeleementにしかアクセスを制限しないようにすることを提案しています。基本的には、配列を使う代わりに、クラス内で 'Collection'(ここでは' List')の "hide"を使います。 –

1

Javaの壊れたジェネリックシステムのために、パラメトリックArray定義を使用することはできませんが、タイプ消去のため、パラメトリックArray宣言に割り当てられたObjectの配列を持つことができます実行時にVMの型システム。 この後、この配列の操作はT型を満たす必要があり、コンパイラはコンパイル時に起こることを確認します。あなたは定義を回避する必要があります。

class ArrayList<V> { 
    private V[] backingArray; 
    public ArrayList() { 
    backingArray = (V[]) new Object[DEFAULT_SIZE]; 
    } 
} 

Java theory and practice: Generics gotchas

+0

これはうまくいくかもしれませんが、マットの答えはそのような配列を初期化する正しい方法です。 –

+0

唯一の違いは、余分な容量パラメータが必要だということです。どちらも同じですが、どちらも未確認の警告を出します。これらは、インスタンス化されたばかりです。 Mine: 'new ArrayList ()'、@Matts: '新しいRingBuffer (Integer.class、10)'、クラスパラメータは完全に冗長であり、不要なリフレクションの使用はVMを遅くします。 –

+0

クラス内でタイプVが消去されているので、配列がクラス内にある限り、これは問題ありません。しかし、メソッドから配列を返すことや、汎用スコープの外にいる誰かがそれを取得できるようになった場合は、 – newacct

3

あなたがT[]にキャストする必要がなく、Object[]

+0

これは以前の私の回答よりもどのように優れていますか?反射はここでは本当に必要ではなく、避けるべきです。 –

+1

あなたのオブジェクトはV []にキャストされているオブジェクトです。* V *へのキャスト* V [] – Matt

+1

このようなコードで型安全性を保証する方法は、バッキングストアが正しいクラスを持っているかどうかを確認することではありません作成時には、タイプ消去後には問題ありません。バッキングストアを変更するメソッド、つまり 'add(T t)'、 'T pop()'などで保証します。 –

0

java.util.ArrayDeque(またはJavaとは対照的に、それは本当にT[]あるこの

private final T[] items; 

public RingBuffer(Class<T> clazz, int capacity) { 
    this.items = (T[]) Array.newInstance(clazz, capacity); 
} 

ような何かを行うことができます。 util.concurrent.ArrayBlockingQueue)はあなたが探しているものです。しかし、独自の循環バッファ/キューを実装することをお勧めします。それはとても良い運動です。

int []キャッシュについては、そうすることをお勧めします。 重要な注意:いくつかのキャッシング機構を使用したい場合は、tomcatが好きではなく、ConcurrentLinkedQueueを使用してください。 キャッシュはスタックを使用しなければなりません。キューではなく、ArrayDequeとArrayBlockingQueueの両方がスタックに適しています。

関連する問題