【问题标题】:Declaring static generic variables in a generic class在泛型类中声明静态泛型变量
【发布时间】:2011-09-28 10:59:22
【问题描述】:

我读到你不能在泛型类中声明静态变量/方法,我真的不知道如何解决我的问题或解决它,所以我请求你的指导。

我想要的是一个通用的“索引”,我的所有核心类都将扩展它。 我正在创建一个游戏引擎,一个例子是我将拥有不同的游戏状态,它们都扩展了State,而它们又扩展了Nexus<State>。我想要静态头部和尾部的原因是我可以保留所有游戏状态的链接列表,因为它们都在创建时添加到该列表中。

另一个例子是我将拥有不同的游戏对象,它们都扩展了GameObject,而它们又扩展了Nexus<GameObject>

这是名为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;

    }

}

如果有人有其他解决方案或解决方法,我会全力以赴!

【问题讨论】:

  • 鉴于静态字段的名称,几乎可以肯定的是,您不应该在这里使用静态字段。无论有没有你的泛型,这都是真的。但是您从哪里读到应该始终避免泛型类中的静态成员?我自己从未听说过,我强烈反对。
  • 这很奇怪,我得到了这个:Game.main(Game.java:29)线程“main”中的异常java.lang.ExceptionInInitializerError 原因:java.lang.RuntimeException:无法编译的源代码- 不能从 Nexus 的静态上下文中引用非静态类型变量 T。(Nexus.java:13) ... 还有 1 个 Java 结果:1
  • @Kirk 谷歌快速搜索“不能从静态上下文引用非静态类型变量”给了我大量的结果,这些结果都说明了我写的内容,很多来自这个网站:/
  • @Tanax 没有。没有人说在泛型类中不能有静态变量,编译器、编译器错误消息或异常也没有。
  • 我很困惑呵呵。第 13 行是这样的:private static T head = null;

标签: java list generics static linked-list


【解决方案1】:

Java 泛型与 C# 泛型完全不同。 有类型擦除,所以你不能说像Nexus&lt;T&gt;.aStaticPublicField 这样的东西(就像在 C# 中一样)。 你只能说Nexus.aStaticPublicField。 无法知道泛型类型是什么(因为您没有实例),因此您不能拥有 T 类型的静态字段。

【讨论】:

  • 是的,这正是我在本网站上有关此问题的所有其他问题中发现的。您知道完成我需要的另一种方法或解决方法吗?
  • @Tanax:你可以保留一个(头,尾)对的字典,按类型键入。
  • @Petar,Nexus&lt;String&gt;.aStaticPublicField 有什么问题?
【解决方案2】:

试试这个方法:定义一个子类实现的protected abstract 方法,为他们的类返回一个static 对象。

可能存在一些逻辑问题等,但答案的基础在这里(即编译):

已编辑:现在 delegating 转为 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
    }
}

【讨论】:

  • 应该可以,但是...重用来自getHeadAndTail 的返回引用,而不是多次调用。
  • 看起来棒极了!我会尝试实现它,看看它是否有效:D
  • 抽象类的构造函数调用虚方法是有问题的。
  • 当我只有一种类型时,这段代码效果很好(我用 2 个不同的游戏状态类对其进行了测试,它们都扩展了 Nexus 的状态)。但是当我添加了一个扩展了 GameObject 的游戏对象时扩展的 Nexus 我遇到了一个异常:Exception in thread "main" java.lang.NullPointerException at Nexus.Add(Nexus.java:35) at Nexus.&lt;init&gt;(Nexus.java:16) at GameObject.&lt;init&gt;(GameObject.java:17) at SpaceShip.&lt;init&gt;(Game.java:47) at Game.main(Game.java:67) 我真的不明白为什么它给了我这个 Nexus,35 是:GetHeadAndTail().tail = ( GetHeadAndTail().tail.next = obj );
  • 哦,我知道了! Num 是静态的并且在所有 Nexus 类之间共享,因此 head 和 tail 永远不会为该类型名初始化,因为 num 不是 0。
【解决方案3】:

根据http://download.oracle.com/javase/tutorial/java/IandI/abstract.html

班级成员 - 抽象类可能有静态字段和静态方法。您可以将这些静态成员与类引用一起使用——例如,AbstractClass.staticMethod()——就像对任何其他类一样。

但我自己还没有测试过这个

【讨论】:

  • 我很确定教程早于泛型。
  • 你不能只输入AbstractClass.staticMethod&lt;type&gt;()
  • 你好汤姆!我认为这里的错误不是抽象,而是泛型( )。
  • 事情是,看看你的代码,我不明白为什么 head 和 tail 会是静态的。您似乎正在实现的是一个单链表,在这种情况下,头和尾不应该是静态的,否则您将只能拥有该类的一个实例,否则任何新实例都会覆盖头和尾对于所有其他实例
  • ((Nexus)obj).next = null;这行也很奇怪,你确定要将传入的对象转换成Nexus对象吗?
【解决方案4】:

一组静态字段并不是实现此目的的好方法。我不太了解您的要求,但似乎更好的方法是更改​​此类的构造函数的签名以传入全局索引对象。

也就是说,而不是这个:

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

...你可以这样做:

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

这适当地分离了跟踪游戏状态和跟踪所有游戏状态索引的职责。 (参见“Single responsibility principle”。)它还明确指出,状态对象的创建依赖于正确索引该状态。

【讨论】:

  • 对不起,也许我在解释我在原始帖子中想要的内容方面做得很差,但我想做的是创建.. 例如扩展 State 的 StateOne(其中包含各种方法)。反过来,State 扩展了 Nexus,因此我创建的 StateOne 实例将自动添加到 Nexus 中的内部静态链表中。我还希望能够创建一个扩展 GameObject(还包含各种方法)的 SpaceShip,后者又扩展 Nexus 所以当我创建 SpaceShip 的实例时,它将被添加到 Nexus 的列表中跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多