开发者

Java: Only allow instantiation by one class

I want certain classes in my project to be pooled. And so I don't want to be able to instantiate these classes using: new SomeClass(), but instead obtain a new item from the pool using SomeClass.allocate(). I have this kin开发者_Go百科d of code for each class that needs pooling.

public class GameObject
{
    // Pooling: Provides a static method for allocation and a method for freeing
    private static Pool<GameObject> pool = new Pool<GameObject>();
    public static GameObject allocate() { return pool.obtain(); }
    public void free() { pool.free(this); }
    ...
}

Now I can disable the normal way of instantiating by making the default constructor private, but the problem is that the pool needs to instantiate the class when it's created, and also when the pool needs to expand.

Is there some way to limit construction to only by the pool?


You have 2 options I can see: either make it an inner-class of the pool or make the allocate method package-private and put it in the same package as the pool.

EDIT: Ah. Just make the constructor private and then override whatever method the Pool uses to create new instances. As a (crude) example using your frame above:

public abstract class Pool<T>
{
    public abstract T getNewObject();

    public T obtain(){ return getNewObject(); }

    public void free(T obj) {}
}

and

public class GameObject
{
    // Pooling: Provides a static method for allocation and a method for freeing
    private static Pool<GameObject> pool = new Pool<GameObject>(){
          public GameObject getNewObject(){ return new GameObject(); }
    };
    public static GameObject allocate() { return pool.obtain(); }
    private GameObject(){}
    public void free() { pool.free(this); }
}

GameObject's constructor is happily inaccessible to anyone else.


As a last resort,you are able to use reflection. For other option,other people already tells. I remember Spring container is able to init class that has private constructor. And I am surprised of that. I guess it also uses this trick. The benefit could be it is more generic.

public static void main(String... args) {
    try {
      Constructor c = GameObject.class.getDeclaredConstructor();
      c.setAccessible(true); // solution
      c.newInstance();

      // production code should handle these exceptions more gracefully
    } catch (InvocationTargetException x) {
      x.printStackTrace();
    } catch (NoSuchMethodException x) {
      x.printStackTrace();
    } catch (InstantiationException x) {
      x.printStackTrace();
    } catch (IllegalAccessException x) {
      x.printStackTrace();
    }
  }


Alterative: Don't try to make your code jump through hoops. Use static analysis to enforce rules like this. The tools will catch it if you accidentally do something that you didn't intend to.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜