I've been having trouble with using generics the right way. I put together a complete example of what I wanted to do, which is below. My problem is that I kept trying to figure out a way for a generic class to produce an instance of the generic type 'internally', which just doesn't want to work without a cast and even that will produce a warning (though it does work). Here is my favorite barn example:
// Barn.java
import java.util.ArrayList;
public class Barn<TAnimal extends Animal>
{
protected ArrayList<TAnimal> m_animals = new ArrayList<TAnimal>();
protected FactoryAnimal m_factory;
public Barn()
{
}
public void addAnimal(TAnimal animal)
{
m_animals.add(animal);
}
public void setFactory(FactoryAnimal factory)
{
m_factory = factory;
}
public void magic()
{
// This won't work even though we know we were
// initialized with a Horse type and that the factory
// is actually producing a Horse instance.
m_animals.add(m_factory.createAnimal());
}
}
// Animal.java
public class Animal
{
public Animal(){}
}
// Horse.java
public class Horse extends Animal
{
public Horse(){}
}
// FactoryAnimal.java
public abstract class FactoryAnimal
{
public abstract Animal createAnimal();
}
// FactoryHorse.java
public class FactoryHorse extends FactoryAnimal
{
public FactoryHorse() {}
public Animal createAnimal()
{
return new Horse();
}
}
// Main driver class.
public class TestGenerics
{
public static void main(String[] args)
{
Barn<Horse> barn = new Barn<Horse>();
barn.setFactory(new FactoryHorse());
// This won't work.
barn.magic();
// This is ok because 'outside' we know Barn
// has been initialized with type Horse.
barn.addAnimal(new Horse());
}
}
Yeah so what I can do is use a cast like:
m_animals.add((TAnimal)m_factory.createAnimal());
inside the Barn class but it will produce a warning and just doesn't look good.
Sorry if it seems like I keep going in circles with this stuff, I was hoping to make this little library as easy to use as possible, and believe my salvation lies within generics!
objects factory is a great solution. If you wanted, you could go for a factory method as well:
class TestGenerics { public static void main(String[] args) throws Exception { Barn<Horse> barn = new Barn<Horse>(); barn.setFactory(new AnimalFactory<Horse>(Horse.class)); // This won't work. barn.magic(); // This is ok because 'outside' we know Barn // has been initialized with type Horse. barn.addAnimal(new Horse()); barn.addAnimal(animalFactoryMethod(Horse.class)); } private static <T extends Animal> T animalFactoryMethod(Class<T> clazz) throws Exception { return clazz.newInstance(); }}
Yeah that looks good, the only thing I wonder about that is that the factory can't create an instance of Horse with initial parameters, like:
public class Horse
{
public Horse(int x, int y) {}
}
return clazz.newInstance();
then the clazz.newInstance() wouldn't work because there's no default no-parameter constructor, right? Just checking,
Thanks
0
An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.
One of a set of tools we're offering as a way of saying thank you for being a part of the community.
Not entirely, the requirement is that all animals should have the same constructor, or knowledge of these constructors need to be present in the factory.
class AnimalFactory<T extends Animal> { private Class<T> clazz; public AnimalFactory(Class<T> c) { this.clazz = c; } public T createAnimal(int x, int y) throws Exception { Constructor<T> tConstructor = clazz.getConstructor(int.class, int.class); return tConstructor.newInstance(x, y); }}
public class AnimalFactory<T extends Animal>
{
private Class<T> clazz;
public AnimalFactory( Class<T> c )
{
this.c = c;
}
public T createAnimal() throws Exception
{
return clazz.newInstance();
}
}