Abstract Item Choosers

import java.util.*;

interface ItemChooser<T>
{
    T getNext();
    T getSentinel();
    int size();
    void reset();
}

abstract class AbstractItemChooser<T> implements ItemChooser<T>
{
    private T sentinel;
    private T[] items;
    private List<T> available;
    
    protected AbstractItemChooser(T[] items, T sentinelValue)
    {
        this.items = items;
        this.sentinel = sentinel;
        available = new ArrayList<T>(items.length);
        reset();
    }
    public T getNext()
    {
        return available.size() > 0 ? available.remove(getIndexOfNext()) : sentinel;
    }
    public T getSentinel()
    {
        return sentinel;
    }
    public int size()
    {
        return available.size();
    }
    public void reset()
    {
        available.clear();
        for (int i = 0; i < items.length; i++)
        {
            available.add(items[i]);
        }
    }
    protected abstract int getIndexOfNext();
}

class RandomItemChooser<T> extends AbstractItemChooser<T>
{
    public RandomItemChooser(T[] items, T sentinel)
    {
        super(items, sentinel);
    }
    protected int getIndexOfNext()
    {
        return (int)(Math.random() * size());
    }
}

class RandomStringChooser extends RandomItemChooser<String>
{
    public RandomStringChooser(String[] strings)
    {
        super(strings, "NONE");
    }
}

public class Items {
    public static <T> void process(ItemChooser<T> chooser)
    {
        while (chooser.size() > 0)
        {
            System.out.print(chooser.getNext() + " ");
        }
        System.out.println();
    }
    public static void main(String args[]) {
        ItemChooser<String> randomChooser, sequentialChooser, reverseChooser;
        randomChooser = new RandomStringChooser(args);
        process(randomChooser);
        //process(sequentialChooser);
        //process(reverseChooser);
    }
}