Solved

Producing a generic correctly

Posted on 2008-06-22
6
184 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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

INTRODUCTION Working with files is a moderately common task in Java.  For most projects hard coding the file names, using parameters in configuration files, or using command-line arguments is sufficient.   However, when your application has vi…
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …

705 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

19 Experts available now in Live!

Get 1:1 Help Now