Search code examples
javagenericsfactory-patternnested-generics

Is there any way to get a class for or instantiate a doubly-generic type in Java?


So say I have:

public class Foo<T> {
  // Some stuff
}

public interface Factory<T> {
  T newInstance();
  Class<T> getKlass();
}

And I want to make an implementation of Factory to build Foo<T>s:

public class FooFactory<T> implements Factor<Foo<T>> {
  private Class<Foo<T>> klass;
  public FooFactory(Class<Foo<T>> klass) {
    this.klass = klass;
  }

  public T newInstance() throws Exception {
    return klass.newInstance();
  }

  public Class<Foo<T>> getKlass() {
    return klass;
  }
}

Two questions:

  1. Is there any way for me to get a Class<Foo<T>> if all I have is Class<T>? Unfortunately Foo is a private class, and therefore the only code that has the whole picture (i.e., knowledge of what T will be) can't know about Foo and therefore can't give me Class<Foo<T>>.
  2. Is there a better way I could be going about this?

Thanks!

P.S. For those asking for more detail, here we go. The full story is that Foo and FooFactory will both be private classes in an outer class. Foo is used extensively throughout the outer class, and to avoid spurious garbage collection, I'd like to use an ObjectPool to instantiate instances of Foo rather than newing them up and having them garbage collected all the time. However, in order to use my ObjectPool, I need a Factory<Foo<T>>, and inside of Outer<T> I obviously can't know what T will be when Outer<T> is instantiated.

public class Outer<T> {
  private class Foo<T> { ... }
  private class FooFactory<T> {...}

  private ObjectPool<Foo<T>> fooPool;

  ...
}

Solution

  • There are ways to create a the type information for Class<Foo<T>> but to do what you want, you simply need to suppress all generics warnings in FooFactory.

    At runtime, Java uses Object in all places where you wrote T, so you can simply instantiate Foo<Object> or Foo.class, they are the same. This is called type erasure.

    Generics are just a hint for the compiler. Since your API makes sure that all code using FooFactory will honor the type T, you can suppress the warnings and use the appropriate casts and it will work.

    Note: If you want to preserve type information, implement the ParameterizedType interface.