【问题标题】:Creating objects of same type as subclass创建与子类相同类型的对象
【发布时间】:2013-05-05 05:10:04
【问题描述】:

我正在设计一个遗传算法库,目前正在构建Genome 类。此类包括用于创建、突变、交叉和评估基因组的几种方法,并将成为该库的核心。这个抽象类有两个子类StaticGenomeVariableGenome。这些类为固定或可变长度的基因组提供了额外的功能。

最终,跨越任何两个基因组应该独立​​于基因组类型。话虽如此,singlePointCrossover(Genome parent2) 方法接受两个基因组,并返回一个新的Genome 对象,它是两个父基因组的特殊组合。但是,因为Genome 是一个抽象类,我不能实例化一个新的Genome 对象,因为它是后代。

如何从超类返回与子类相同类型的新对象?

任何帮助将不胜感激。

Genome 类:

public abstract class Genome <ElementType> {
    private String name;
    private List<AbstractGenomeElement<ElementType> > elements;

    // Mutation Methods //////////////////////////////////////////////
    public AbstractGenomeElement<ElementType> mutateElement(AbstractGenomeElement<Integer> element) {
        return this.mutateElementAtIndex(this.getElements().indexOf(element));
    }

    public AbstractGenomeElement<ElementType> mutateElementAtIndex(int i) {
        return this.getElement(i).mutate();
    }

    // Crossover Methods //////////////////////////////////////////////
    public Genome<ElementType> singlePointCrossover(Genome<ElementType> genome2){
        return multiPointCrossover(genome2, 1);
    }

    public Genome<ElementType> twoPointCrossover(Genome<ElementType> genome2){
        return multiPointCrossover(genome2, 2);
    }

    public Genome<ElementType> multiPointCrossover(Genome<ElementType> genome2, int crosses){
        List<AbstractGenomeElement<ElementType>> newElements= new ArrayList<AbstractGenomeElement<ElementType>>();
        Integer nums[] = new Integer[length-1];

        for (int i = 0; i < length-1; i++) { nums[i] = i+1; }

        List<Integer> shuffled = Arrays.asList(nums);
        Collections.shuffle(shuffled);
        shuffled = shuffled.subList(0, crosses);
        boolean selectFromParentA = true;
        for(int i = 0; i < length; i++){
            if(shuffled.contains((Integer)i)){
                selectFromParentA = !selectFromParentA;
            }
            if(selectFromParentA) newElements.add(this.getElement(i));
            else newElements.add(genome2.getElement(i));
        }
        // Code fails at this point. "Can not instantiate the type Genome"
        return new Genome<ElementType>(name, newElements);
    }
}

两个子类:

public class StaticGenome<ElementType> extends Genome<ElementType> {

}

public class VariableGenome<ElementType> extends Genome<ElementType> {

}

以及我用于测试的主要方法:

public static void main(String [] args){
    Genome<IntegerElement> genomeA = new StaticGenome<IntegerElement>("Genome A", 50);
    Genome<IntegerElement> genomeB = new StaticGenome<IntegerElement>("Genome B", 50);

    Genome<IntegerElement> offspring = genomeB.uniformCrossover(genomeA.elementCrossover(genomeA.multiPointCrossover(genomeB, 3)));
    offspring.setName("Offspring");
    System.out.println(offspring);
}

【问题讨论】:

  • 阅读上面的帖子,我可以看到基因组只能是两种类型的静态基因组和可变基因组。现在,当您想要返回基因组时,它将属于这两种类型中的任何一种。对吗?
  • 我想,是的。目前,我没有想到任何其他基因组实现,但我可以想象有人可能想要创建一个新的子类2DGenome 或其他东西,具有额外的功能。

标签: java inheritance types subclass superclass


【解决方案1】:

您可以将以下方法引入抽象类并在子类中实现。

protected abstract Genome<ElementType> newInstance(String name, List<AbstractGenomeElement<ElementType>> elements);

当子类实现这一点时,它们可以返回正确的实例。即:他们自己的一个新实例。在您的交叉方法中,您可以调用此方法而不是执行“新基因组”

【讨论】:

    【解决方案2】:

    你可以从一个被覆盖的方法返回一个子类,它被称为协变返回类型

    abstract class Genome {
        abstract Genome singlePointCrossover(Genome parent2); 
    }
    
    class StaticGenome extends Genome {
        @Override
        StaticGenome singlePointCrossover(Genome parent2) {
            ...
        }
    }
    
    class VariableGenome extends Genome {
        @Override
        VariableGenome singlePointCrossover(Genome parent2) {
            ...
        }
    }
    

    【讨论】:

    • 问题是,分频器的工作原理是一样的,无论是可变长度还是静态长度。所以我想将该代码放在Genome 类中,这样我就不会重复代码
    • docs.oracle.com/javase/tutorial/java/IandI/abstract.html "与接口不同,抽象类可以包含非静态和最终的字段,它们可以包含已实现的方法。"将Genome 设为抽象类,但不要将singlePointCrossover() 设为抽象。
    • 是的,我刚刚意识到我完全错过了你的问题(实际问题),对不起:(
    【解决方案3】:

    如果我是对的,那么问题是:给定一些 Genome 对象(这将是抽象类 Genome 的某个子类),我们如何实例化该子类的新实例?

    好吧,我不知道这是否是最好的方法,但这是我想出的:

    public Genome<ElementType> 
    multiPointCrossover(Genome<ElementType> genome2, int crosses){
        // Snip...
        Genome g;
        try {
            g = genome2.getClass()
                    .getConstructor(String.class, List.class)
                    .newInstance();
        } catch (Exception e) {
            // Can throw quite a few exceptions...
        }
        return g;
    }
    

    http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getConstructor(java.lang.Class...) http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/reflect/Constructor.html#newInstance(java.lang.Object...)

    注意:我认为 Dev Blanked 的解决方案更干净、更易于使用。这正是我在他们发布时想出的。

    【讨论】:

      【解决方案4】:

      我认为您需要在 Genome 和 Static/VariableGenome 类之间再引入一个类。我不是微生物学专家,所以不能给它推荐一个合乎逻辑的好名字。但是,如果您有一个新的 Genome 子类(比如说 newGenomeClass)并充当您的 Static/VriablGenome 类的父类,那么您可以使用这样的方法:

      public newGenomeClass singlePointCrossover(newGenomeClass parent1,newGenomeClass parent2).
      

      希望对你有帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-02
        • 1970-01-01
        • 2014-04-04
        • 2014-05-24
        相关资源
        最近更新 更多