【问题标题】:Instantiating a generic extension of an abstract class实例化抽象类的通用扩展
【发布时间】:2011-10-05 13:54:19
【问题描述】:

尝试为遗传算法编写一些通用代码,我有一个抽象类 Genotype 如下:

public abstract class Genotype {
private ArrayList<Gene> genotype = new ArrayList<Gene>();

//...

public Genotype(ArrayList<Gene> genotype) {
    setGenotype(genotype);
    setGenotypeLength(genotype.size());
}

public abstract Phenotype<Gene> getPhenotype();

public abstract void mutate();

//...
}

这个类是用来扩展的,子类显然提供了getPhenotype()和mutate()的实现。但是,我还有第二个类,它接受两个 Genotype 对象作为参数并返回一个包含 Genotype 对象的 ArrayList。由于此时我不知道扩展 Genotype 对象的类型,因此我需要使用如下通用参数:

public class Reproducer {

//...

    private <G extends Genotype> ArrayList<Genotype> crossover(G parent1, G parent2) {
        ArrayList<Genotype> children = new ArrayList<Genotype>();

        ArrayList<Gene> genotypeOne = ArrayListCloner.cloneArrayList(parent1.getGenotype());
        ArrayList<Gene> genotypeTwo = ArrayListCloner.cloneArrayList(parent2.getGenotype());

        //one point crossover
        int p = gen.nextInt(genotypeOne.size());

        for (int i = 0; i < p; i++) {
            genotypeOne.set(i, genotypeOne.get(i));
            genotypeTwo.set(i, genotypeTwo.get(i));
        }
        for (int i = p; i < 10; i++) {
            genotypeOne.set(i, genotypeTwo.get(i));
            genotypeTwo.set(i, genotypeOne.get(i));
        }

        children.add(new G(genotypeOne)); //THROWS ERROR: Cannot instantiate the type G
        children.add(new G(genotypeTwo)); //THROWS ERROR: Cannot instantiate the type G

        return children;
    }
}

但是,由于我需要在 ArrayList 中返回两个 G 类型的对象,我显然有一个问题,即我无法实例化新的 Genotype 对象,因为它们是 1. 泛型类型,并且可能是 2. 抽象的。

这可能是一种不好的方式来处理所有事情,但如果有人有一个很棒的解决方案。谢谢。

【问题讨论】:

    标签: java generics parameters abstract instantiation


    【解决方案1】:

    我建议在 Genotype 类中使用工厂方法

    public abstract class Genotype {
         public abstract GenoType newInstance();
    }
    

    【讨论】:

    • 谢谢,这不是必须是静态方法吗?显然我不能有一个抽象的静态方法。
    • @carnun,不应该。只需在您的 GenoType 实例上调用它,例如 GenoType g = parent1.newInstance()。如果您愿意,也可以添加参数。
    • 这太棒了!谢谢约翰。解决了一个非常相似的问题,并使我的代码提高了 100 倍。我在一个抽象类中有一个最终的泛型数组,我的编译器不会停止抱怨。
    【解决方案2】:

    您可以使用abstract factory pattern。由于您的工厂中只需要一个工厂方法,这可以说是一种退化的情况,但它可能正是您所需要的。您应该将工厂实例传递给您的 Reproducer 对象,可能作为某个方法的参数。它并不漂亮,但至少您现在对对象创建有了抽象。

    更好的解决方案可能是更改您的架构。为什么不忘记Genotype 类?您的基因型表示基本上是基因列表。您可以在这些列表上创建一个具有(通用)操作的实用程序类,并在您的其他类中使用这些操作。以下是我的意思的草图:

    public static <G extends Gene> List<? extends G> mutate( List<G> genotype ) { ... }
    public static <G extends Gene> List<List<? extends G>> crossover( List<G> p1, List<G> p2 ) { ... }
    

    附带说明:倾向于声明接口类型而不是类类型;在您的示例中,您没有使用 List 接口。

    最后附注:在您的示例中,您实际上并不需要泛型类型。如果您将参数类型声明为Genotype,您将获得相同的解决方案(同样的问题)。 X 类型参数接受任何 X 类型的对象(包括子类型!)作为参数。

    【讨论】:

      猜你喜欢
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多