【问题标题】:Java Generic Container ClassJava 通用容器类
【发布时间】:2011-02-05 23:37:32
【问题描述】:

我正在研究一个用 Java 实现的进化模拟模型,但遇到了一个我似乎无法解决的关键面向对象设计问题。问题可以总结如下:

我有一个基本抽象类 Player 和两个具体的子类 Signaller 和 Receiver:

abstract class Player
{
    Strategy[] strategies;
    double fitness;
    ...
}

class Signaller extends Player
{
    double quality;
    ....
}

class Receiver extends Player
{
    double[] weights;
    int chosenChannel;
    ....
}

现在我需要代表 Signalers 和 Receivers 集合的类,并且我只能使用数组来存储它们。有两种群体类型共有的方法,但也有针对信号者群体或接收者群体的特定方法。

概念上,我需要这样的东西:

abstract class Population
{
    Player[] members;

    void mixUpPopulation() {...}
    Strategy[] getMeanStrategies() {...}
    double getMeanFitness() {...}
    ...
}

class SignallerPopulation extends Population
{
    Signaller[] members;
    ...
}

class ReceiverPopulation extends Population
{
    Receiver[] members;

    double[] getChannelPreferences() {...}
    ...
}

我已经想到了两种实现这一目标的基本方法:

  1. 具有如上所述的类层次结构。
    问题:超类中的Player[]以及子类中的Signaller[]Receiver[]如何引用相同的对象集合?

  2. 使基类通用:

class Population <T extends Player>
{
    ...    
    T[] members = (T[])new Object[popSize];
}

问题:如何实现针对每种人口类型的特定方法?

感谢您对这些问题的见解或对解决问题的其他方法的建议。

【问题讨论】:

  • 我认为数组和泛型会带来麻烦。尝试编译建议的第二条语句...为什么不使用 ArrayList
  • 我只能使用数组来存储它们 - 为什么?
  • 嗨@Alex,如果你已经解决了,你能发布工作示例吗?我发现很难理解这个示例。我们将不胜感激。
  • @Karussell 您对数组和泛型的看法是正确的,没有优雅的方式来处理这种组合。这就是我决定不使用它的原因。
  • @Paŭlo Ebermann 我需要使用数组的原因更复杂,超出了我的问题范围。简而言之,我的模拟运行速度将比其他类型的集合更快。

标签: java generics inheritance


【解决方案1】:

您可以在问题中使用设计 1,但不是将数组存储在抽象基类中,而是添加一个抽象受保护方法(例如 getMembers()),该方法将在子类中实现以返回实际数组为玩家数组。

或者,您可以使抽象基类通用,并派生具有适当类型的子类:

abstract class Population<T extends Player>
{
    T[] members;

    void mixUpPopulation() {...}
    Strategy[] getMeanStrategies() {...}
    double getMeanFitness() {...}
    ...
}

class SignallerPopulation extends Population<Signaller>
{
    public SignallerPopulation(int popSize) { members = new Signaller[popSize]; }
    ...
}

class ReceiverPopulation extends Population<Receiver>
{
    public ReceiverPopulation(int popSize) { members = new Receiver[popSize]; }
    double[] getChannelPreferences() {...}
    ...
}

【讨论】:

  • 在这种情况下,T[] 仍然需要由子类管理(至少实例化),因为您无法创建泛型类型的数组(之后不使用反射和未经检查的强制转换) .
  • 我决定使用第一个选项,并且您提出的建议(使用超类中的抽象方法)效果很好。我将在下面的答案中给出我的代码草图。非常感谢您的帮助。
【解决方案2】:

Population 中删除members 并向其添加成员的抽象getter 方法(public abstract Player getMember(int i)public abstract int getNumPlayers() 或类似的东西)。实现 getter 需要子类。这样您仍然可以访问PopulationXYPopulation 成员的Player 部分。

【讨论】:

  • 感谢您的建议(基本上与@Medo42 提出的第一个选项相同)。我用过,效果很好。
【解决方案3】:

我采用了@Medo42(他的第一个选项)和@LumpN 建议的设计。唯一需要的演员是在设置数组时,但这不是问题。我在这里给出代码的大纲,也许有人会觉得它有帮助。

abstract class Population
{
    protected abstract Player[] getMembers();  
    protected abstract void setMembers(Player[] members);    

    void mixUpPopulation() {...}
    Strategy[] getMeanStrategies() {...}
    double getMeanFitness() {...}
    ...
}

class SignallerPopulation extends Population
{
    Signaller[] members;

    protected Player[] getMembers() 
    {
        return this.members;
    }

    protected void setMembers(Player[] members) 
    {
        this.members = (Signaller[]) members; //required cast
    }
    ...
}

class ReceiverPopulation extends Population
{
    Receiver[] members;

    protected Player[] getMembers() 
    {
        return this.members;
    }

    protected void setMembers(Player[] members) 
    {
        this.members = (Receiver[]) members; //required cast
    }

    double[] getChannelPreferences() {...}
    ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多