【问题标题】:Generic ObjectPool - how to return a generic class?Generic ObjectPool - 如何返回一个泛型类?
【发布时间】:2014-01-15 07:14:16
【问题描述】:

我正在尝试开发一个 ObjectPool,它可以与任何 Object 一起使用,而无需更改 Pool 或 Object 的源 - 但我找不到任何方法来编写 get()-function(“Maincode”从池中获取一些对象),因为存在类型不匹配(无法从对象转换为测试对象)

到目前为止,这是我的代码:

对象池:

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

【问题讨论】:

  • 如果这将被多个请求调用,我会在这里看到一个线程问题。
  • 所以我最好将它与 synchronized 一起使用?
  • 是的,您需要同步该部分...您永远不想允许从列表中添加/删除超过 1 个线程...
  • 还有其他问题吗?假设在类级别声明了一个类型参数 T,那么在您更新之后,您似乎走在了正确的轨道上。
  • 主代码仍然存在我无法解决的类型不匹配

标签: java generics object-pooling


【解决方案1】:

你不是在池中:你只是在使用对象的一个​​实例。

通用对象池如下所示:

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);
        }
    }
}

很遗憾,我没有编译器来测试代码,但它应该会提示您要更改的内容。

【讨论】:

  • 这几乎正是我所寻找的 (update2) - 到目前为止唯一的问题是编译错误:向对象添加 newInstance 时出现“未处理的异常类型 IllegalAccessException” - 顺便说一句,不应该我在将对象返回池时“重置”/重新初始化它?
  • newInstance() 需要公共默认构造函数。我会稍微修改一下代码,这样你就可以通过重写方法来创建没有默认构造函数的类的实例
【解决方案2】:

哦,在你的主代码中

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));
}

【讨论】:

  • 忘记了 - 现在可以使用了!感谢您的提示,没有意识到 .remove() 实际上返回了一些东西
【解决方案3】:

你可以试试:

public <T> T get() {
    // Your code for objectToReturn
    return (T) objectToReturn;
}

【讨论】:

  • 你不会使用通用的ArrayList(或Queue)吗?
  • @BheshGurung 在什么情况下会发生这种情况?
  • 泛型的目的之一是类型安全,你不想要这样的显式转换。在这种情况下会推断出实际类型,如果您使用错误的类型来创建引用,那么您将获得 CCE。
  • 使类本身泛型,假设池中的所有对象都属于同一类型。
  • -1 这比强迫调用者投射更糟糕,因为调用站点上没有明显的迹象表明可能会出错。使用此代码,调用者可以请求 List&lt;String&gt; 并获得 List&lt;Integer&gt;,然后在稍后遇到莫名其妙的 ClassCastException
猜你喜欢
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多