Generic ObjectPool — как вернуть универсальный класс?

Я пытаюсь разработать ObjectPool, который можно использовать с любым объектом без изменения источника ни пула, ни объекта, но я не могу найти способ написать функцию get() («Основной код» получает некоторый объект из пула), поскольку существует несоответствие типа (невозможно преобразовать из объекта в TestObject)

Вот мой код:

Объектный пул:

public Object get() {
        int first = availableObjects.get(0);
        availableObjects.remove(0);
        return objects.get(first);
    }

В objects (ArrayList) находятся все объекты в пуле, availableObjects просто содержит список всех доступных объектов. Я в основном просто возвращаю первый доступный объект и помечаю его как недоступный.

Основной код:

    TestObject test = objectPoolS.get();


Как сделать метод get() более общим/конкретным, чтобы он работал без адаптации пула каждый раз, когда я использую другой класс, и без синтаксического анализа основного кода?


Обновление:

Как правильно будет выглядеть метод get() в более общей версии этого пула?
(Любые другие отзывы приветствуются!)
Обновление: Рабочая (исправленная) версия MainCode ниже

Обновление 2:
Я только что понял, что это не может работать так, мне нужно создавать новые объекты в пуле, что вряд ли возможно сделать без адаптации пула для каждого типа объектов. .
Могу ли я как-то удалить связь между всеми объектами в пуле? (Поскольку я использую baseObject для инициализации всех объектов, на самом деле у меня есть только 5 ссылок на 1 объект)
Или есть лучший способ управлять этим? (Не заставляя пользователя создавать объекты в своем коде)

Полный код до сих пор:

Объектный пул

public class ObjectPoolS<T> {

    int numberOfObjects;
    boolean autoExtending;

    T baseObject;
    ArrayList<T> objects;
    ArrayList<Integer> availableObjects;


    public  ObjectPoolS(T baseObject, int capacity, boolean allowAutoExtending) {
        this.numberOfObjects = capacity;
        this.baseObject = baseObject;
        this.autoExtending = allowAutoExtending;

        objects = new ArrayList<T>(capacity);
        availableObjects = new ArrayList<Integer>(capacity);

        initialize(baseObject, capacity);
    }


    private void initialize(T baseObject, int capacity) {

        // Initialize List of Objects
        for(int i = 0; i < capacity; i++) {
            objects.add(baseObject);
        }

        // Initialize Index of Objects
        for(int i = 0; i < capacity; i++) {
            availableObjects.add(new Integer(i));
        }
    }


    public T get() {
        int first = availableObjects.get(0);
        availableObjects.remove(0);
        return objects.get(first);
    }
}

Основной код (исходный)

ObjectPoolS objectPoolS = new ObjectPoolS(new TestObject(0), 5, true);
TestObject test = objectPoolS.get();

Основной код (фиксированный)

ObjectPoolS<TestObject> objectPoolS = new ObjectPoolS<TestObject>(new TestObject(0), 5, true);
TestObject test = objectPoolS.get();

TestObject содержит только один int для целей тестирования.

Ошибка

Type mismatch: cannot convert from Object to TestObject

person Benjamin Schwalb    schedule 27.12.2013    source источник
comment
я вижу здесь проблему с потоками, если это будет вызываться несколькими запросами.   -  person T McKeown    schedule 27.12.2013
comment
поэтому мне лучше использовать его с synchronized?   -  person Benjamin Schwalb    schedule 27.12.2013
comment
да, вам нужно будет синхронизировать эту часть... вы НИКОГДА не хотите, чтобы более 1 потока добавлялось/удалялось из списка...   -  person T McKeown    schedule 27.12.2013
comment
Есть ли оставшиеся проблемы? После вашего обновления похоже, что вы на правильном пути, если предположить, что параметр типа T объявляется на уровне класса.   -  person Paul Bellora    schedule 27.12.2013
comment
В основном коде все еще есть несоответствие типов, которое я не могу решить.   -  person Benjamin Schwalb    schedule 27.12.2013
comment
Вы объявляете свой класс, например. class ObjectPool<T> ? Пожалуйста, добавьте к вашему вопросу SSCCE и ошибку компилятора. Я также рекомендую не принимать существующий ответ, потому что это небезопасное решение.   -  person Paul Bellora    schedule 28.12.2013
comment
@PaulBellora обновил мой вопрос, он должен содержать все необходимое - я не приму ответ, как только появится лучший.   -  person Benjamin Schwalb    schedule 28.12.2013


Ответы (3)


Вы не объединяете: вы используете только один экземпляр объекта.

Общий пул объектов выглядит примерно так:

public class ObjectPool<T> {
    private List<T> objects;
    private Class<T> clazz;
    private int size;

    public ObjectPool(Class<T> clazz, int size) throws IllegalStateException {
        this.clazz = clazz;
        this.size = size;
        this.objects = new ArrayList<T>();
        for (int i = 0;i < size;i++) {
            objects.add(newInstance());
        }
    }

    // You can override this method with anonymous class
    protected T newInstance() {
        try {
            return clazz.newInstance()
        } catch (Exception exception) {
            throw new IllegalStateException(exception);
        }
    }

    public synchronized T getInstance() {
        if (objects.isEmpty()) {
            return null;
        }
        return objects.remove(objects.size() - 1);
    }

    public synchronized void returnInstance(T instance) {
        if (objects.size() < size) {
            objects.add(instance);
        }
    }
}

К сожалению, у меня нет компилятора для проверки кода, но он должен подсказать, что нужно изменить.

person Sami Korhonen    schedule 28.12.2013
comment
Это в значительной степени именно то, что я искал (update2) - пока единственная проблема - это ошибка компиляции: тип необработанного исключения IllegalAccessException при добавлении newInstance к объектам - Кстати, не должен ли я сбрасывать/повторно инициализировать объект, возвращая его в бассейн? - person Benjamin Schwalb; 28.12.2013
comment
newInstance() требует общедоступного конструктора по умолчанию. Я немного изменю код, чтобы вы могли создавать экземпляры классов, у которых нет конструктора по умолчанию, переопределяя метод - person Sami Korhonen; 28.12.2013

О, в вашем основном коде

ObjectPoolS objectPoolS = new ObjectPoolS(new TestObject(0), 5, true);

you must add "<TestObject>" and becomes

ObjectPoolS<TestObject> objectPoolS
=new ObjectPoolS<TestObject> (new TestObject(0),5,true);

just like where you declare ArrayList, it contains "<T>" and "<Integer>", isn't it?

Однако я считаю, что в вашем исходном коде не должно быть проблем. Это может быть другая проблема.

Советы: в методе get() вы можете переписать:

public T get(){
    return this.list.get(this.available.remove(0));
}
person Valen    schedule 28.12.2013
comment
Забыл об этом - теперь работает! Спасибо за подсказку, не знал, что .remove() действительно что-то возвращает - person Benjamin Schwalb; 28.12.2013

Ты можешь попробовать :

public <T> T get() {
    // Your code for objectToReturn
    return (T) objectToReturn;
}
person fastcodejava    schedule 27.12.2013
comment
Разве вы не использовали бы общий ArrayList (или Queue)? - person Tom Hawtin - tackline; 27.12.2013
comment
@BheshGurung, в какой ситуации это произойдет? - person Benjamin Schwalb; 27.12.2013
comment
Одной из целей дженериков является безопасность типов, вам не нужен такой явный приведение. В этом случае фактический тип выводится, и если вы используете неправильный тип для создания ссылки, вы получаете CCE. - person Bhesh Gurung; 27.12.2013
comment
Что бы вы порекомендовали вместо этого? - person Benjamin Schwalb; 27.12.2013
comment
Сделайте сам класс универсальным, предполагая, что все объекты в пуле относятся к одному типу. - person Bhesh Gurung; 27.12.2013
comment
@BheshGurung еще не совсем работает - пожалуйста, взгляните на мой обновленный вопрос - person Benjamin Schwalb; 27.12.2013
comment
-1 Это хуже, чем заставлять звонящего кастовать, потому что на месте звонка нет видимых признаков того, что что-то может пойти не так. С помощью этого кода вызывающий абонент может запросить List<String> и вместо этого получить List<Integer>, а затем столкнуться с необъяснимым ClassCastException позже. - person Paul Bellora; 27.12.2013
comment
Не должно быть никакого способа вернуть класс/объект, отличный от предусмотренного/ожидаемого в моем коде, но в целом я согласен. - person Benjamin Schwalb; 27.12.2013