2

I want to use the class information that was captured by the setup of a generic method in Java to potentially create an instance. But I can't see how to reference the class without an actual instance. Is it possible?

public class Fancy {

static public <TypeToFind> TypeToFind createInSomeCase() {
  // any type of logic with TypeToFind "class" generic will do, I just want to reference it.

  // the below code is invalid, I could also declare a variable, but can't always create an instance to get the class
  if (TypeToFind.getClass().equals(Something.class)) {
    return TypeToFind.getInstance();
  }
}


}

... so later on I could do:

TheResultIsTheParameter t = Fancy.createInSomeCase();

... instead of

TheResultIsAParameter t = Fancy.createInSomeCase(TheResultIsAParameter.class);

... or

TheResultIsAParameter t = Fancy.createInSomeCase(t);

Am I making this too complicated?

cgp
  • 41,026
  • 12
  • 101
  • 131
  • 1
    possible duplicate of [Instantiating a generic class in Java](http://stackoverflow.com/questions/1090458/instantiating-a-generic-class-in-java) –  Jan 12 '12 at 22:19
  • @JarrodRoberson Similar issues, but not the same answer. Trying to achieve something different and thus the answer ends up being different. +1 all the same - gives more info – cgp Jan 13 '12 at 03:10

3 Answers3

6

You can't do it, because generics are lost at runtime (due to type erasure). You have to pass a Class<?> parameter

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
1

Well, you require somethink that is logical, unfortunattelly generics in Java are only a syntactic sugar for reflection.

List<MyClass> list;
(...)
MyClass my = list.get(0);

will compile to

MyClass my = (MyClass) list.get(0);

and this is what will you see in bytecode.

What is more, using reflection or casting to untyped list you can put any object into list and in both codes you'll get ClassCastException.

So the generics exists only on compiler level. A big feature which adds nothing new, only shortens a code in most cases.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
1

As long as you do not try and statically (at compile time) reference any particular class, nothing prevents you from doing something like this:

public class GenericsTest {
   @Test
   public void testMe() {
      GenericsTest test = new GenericsTest();
      System.out.println(test.get("Hello").getClass());
   }

   public GenericsTest() {
      super();
   }

   public <T extends Object> T get(T entity) {
      return newInstanceForClass((Class<T>)entity.getClass());
   }

   public <T extends Object> T newInstanceForClass(Class<T> clazz) {
      try {
         return clazz.newInstance();
      } catch (Exception e) {
         e.printStackTrace();
         return null;
      }
   }
}

But as you can see, you need to pass in an object of the class you are trying to instantiate, which might not be want you are after. In which case the only other option is to pass in a Class parameterized with the generic type, for reasons that other posters have eloquently stated.

Perception
  • 79,279
  • 19
  • 185
  • 195
  • 1
    This assumes that you are willing to require the user to pass in an instance of the object that they're interested in instantiating (which I don't think the OP wants), and that you're more interested in the actual runtime type of that object than in the compile-time type defined in code. – StriplingWarrior Jan 12 '12 at 22:25