Solved

Producing a generic correctly

Posted on 2008-06-22
6
189 Views
Last Modified: 2010-03-30
Hi,

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!

Thanks
0
Comment
Question by:DJ_AM_Juicebox
  • 2
  • 2
  • 2
6 Comments
 
LVL 92

Accepted Solution

by:
objects earned 300 total points
ID: 21842775
you can use a bit of reflection for that case, something like:

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();
   }
}

0
 
LVL 13

Assisted Solution

by:Bart Cremers
Bart Cremers earned 200 total points
ID: 21844011
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();

    }

}

Open in new window

0
 

Author Comment

by:DJ_AM_Juicebox
ID: 21862548
Hi guys,

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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 92

Expert Comment

by:objects
ID: 21862570
thats correct, that approach would require a default constructor
0
 

Author Comment

by:DJ_AM_Juicebox
ID: 21862576
ok thanks
0
 
LVL 13

Expert Comment

by:Bart Cremers
ID: 21862979
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);

    }

}

Open in new window

0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Unable to open debugger port in Intellij idea 6 139
where is session ID cache stored 1 46
mapAB Challlenge 35 123
Impossible to extract MSI from new JAVA releases 2 47
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

943 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now