开发者

Declaring static generic variables in a generic class

I've read that you cannot declare static variables/methods inside a generic class and I really have no idea how to solve my problem or work around it so I ask for your guidance.

What I want is a generic "index" that all of my core classes will extend. I'm creating a game-engine and an example is that I will have different gamestates who all extends State who in turn extends Nexus<State>. The reason I want the static head and tail is so that I can keep a linked list of all gamestates since they're all added to that list upon creation.

Another example is 开发者_Python百科that I will have different gameobjects who all extends GameObject who in turn extends Nexus<GameObject>.

This is the index called Nexus:

public abstract class Nexus<T> 
{

    private static T head = null;
    private static T tail = null;

    private T next = null;
    private static int num = 0;

    protected Nexus() { this.Add( (T)this ); }

    public T Add( T obj )
    {

        ((Nexus)obj).next = null;
        if( num++ == 0 ) head = tail = obj;
        else             tail = ( tail.next = obj );

        return obj;

    }

}

If anyone got another solution or a workaround I'm all ears!


Java generics are quite different than C# generics. There is type erasure, so you can't say something like Nexus<T>.aStaticPublicField (as in C#). You can only say Nexus.aStaticPublicField. There is no way to know what the generic type is (as you don't have an instance), so therefore you can't have a static field of type T.


Try this approach: Define a protected abstract method that subclasses implement to return a static object for their class.

There may be some logic issues etc, but the basics of the answer are here (ie this compiles):

EDITED: Now delegating to HeadAndTail

/** <T> A subclass of Nexus */
abstract class Nexus<T extends Nexus<T>> { // This syntax lets you confine T to a subclass of Nexus
    private T next;

    protected Nexus() {
        this.add((T) this);
    }

    public T add(T obj) {
        // Delegate to HeadAndTail
        return getHeadAndTail().add(obj);
    }

    /** @return a static for the class */
    protected abstract HeadAndTail<T> getHeadAndTail();
}

/** Bundled into one Object for simplicity of API */
class HeadAndTail<T extends Nexus<T>> {
    T head = null;
    T tail = null;
    int num = 0;

    public T add(T obj) {
        obj.next = null;
        if (num++ == 0)
            head = tail = obj;
        else
            tail = tail.next = obj;

        return obj;
    }
}

class ConcreteNexus extends Nexus<ConcreteNexus> {
    // This is the static object all instances will return from the method
    private static HeadAndTail<ConcreteNexus> headAndTail = new HeadAndTail<ConcreteNexus>();

    protected HeadAndTail<ConcreteNexus> getHeadAndTail() {
        return headAndTail; // return the static
    }
}


according to http://download.oracle.com/javase/tutorial/java/IandI/abstract.html

Class Members - An abstract class may have static fields and static methods. You can use these static members with a class reference—for example, AbstractClass.staticMethod()—as you would with any other class.

But I haven't yet tested this myself


A set of static fields is not a very good way to achieve this. I don't quite understand your requirements but it seems like a better way would be to change the signature of the constructor for this class to pass in the global index object.

That is, instead of this:

protected Nexus() { this.Add( (T)this ); }

... you could do this instead:

protected Nexus(GameStateIndex<T> index) { index.Add(this); }

This properly separates the responsibilities of tracking the game state and keeping track of the index of all game states. (See the "Single responsibility principle".) It also makes it explicitly clear that creation of a state object comes with a dependency on indexing that state properly.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜