我正在设计遗传算法库,目前正在构建Genome
类。该类包括用于创建,变异,交叉和评估基因组的几种方法,并且将是该库的核心。此抽象类有两个子类StaticGenome
和VariableGenome
。这些类为固定或可变长度的基因组提供了额外的功能。
最终,穿越任何两个基因组应该独立于基因组类型。话虽如此,方法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);
}
答案 0 :(得分:3)
您可以将以下方法引入抽象类并在子类中实现它。
protected abstract Genome<ElementType> newInstance(String name, List<AbstractGenomeElement<ElementType>> elements);
当子类实现它时,它们可以返回正确的实例。即:他们自己的新实例。在您的交叉方法中,您可以调用此方法而不是“新基因组”
答案 1 :(得分:1)
您可以从overriden方法返回一个子类,它被称为co-variant return type
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) {
...
}
}
答案 2 :(得分:1)
如果我是正确的,问题是:给定一些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的解决方案更简洁,更易于使用。这就是他们发布时我想出的。
答案 3 :(得分:0)
我认为你需要在Genome和Static / VariableGenome类之间再引入一个类。我不是微生物学专家,所以不能推荐一个好的逻辑名称。但是如果你有一个新的子类(比如说newGenomeClass)你的基因组并充当你的Static / VriablGenome类的父类,那么你可以使用这样的方法:
public newGenomeClass singlePointCrossover(newGenomeClass parent1,newGenomeClass parent2).
希望它有所帮助!