Instantiating a generic extension of an abstract class
Trying to write some generalised code for Genetic Algorithms and I have an abstract class Genotype as follows:
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();
//...
}
This class is intended to be extended and the subclass obviously provides the implementation of getPhenotype() and mutate(). However, I also ha开发者_JAVA百科ve a second class that takes two Genotype objects as parameters and returns an ArrayList containing Genotype objects. Since I don't know the type of the extended Genotype objects at this point I need to use a generic parameter as follows:
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;
}
}
However, since I need to return two objects of type G in an ArrayList I clearly have a problem where I can't instantiate the new Genotype objects because they're 1. generic types and presumably 2. abstract.
This might be a bad way of going about things all together but if anyone has a solution that would be great. Thank you.
I would suggesting using a factory method in your Genotype
class
public abstract class Genotype {
public abstract GenoType newInstance();
}
You could use an abstract factory pattern. Since you need only one factory method in your factory this is arguably a degenerate case, but it might be what you need. You should pass the factory instance to your Reproducer
object, probably as a an argument of some method. It's not pretty, but at least you now have abstraction over object creation.
A better solution would probably be to change your architecture. Why not forget about the Genotype
class? Your genotype representation is basically a list of genes. You could make a utility class with (generic) operations on these lists and use these operations in your other classes. The following is a sketch of what I mean:
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 ) { ... }
As a side note: favour declaring interface types over class types; in your example you don't use the List
interface.
As a final side note: in your example you don't really need the generic type. If you declare the parameter types as Genotype
you get the same solution (with the same problem). A type X parameter accepts any object of type X (including subtypes!) as argument.
精彩评论