1

I want to create an instance just by defining the type for a generic class

public abstract class Base<T> {
    private final T genericTypeObject;

    protected Base(){
          //Create instance of T here without any argument

    }
}

So that I just can call the default constructor:

public class Child extends Base<SomeClass>{
    public Child () {
        super();
    }
}

and the Base-class implementation will create me an instance of the GenericType.

Spektakulatius
  • 2,195
  • 1
  • 21
  • 37
  • 1
    You may be asking an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), and so yu may be better off explaining your overall problem and not how you're trying to (incorrectly) solve it. – Hovercraft Full Of Eels Jul 27 '17 at 12:31
  • Do you want a "clean" solution, or would you be happy with a dirty, reflection-based hack? I was trying to do something like that once, I've given up, but lately I think I've figured it out - though it's really hacky. If that suits you, I can try to finally do that. – Filip Malczak Jul 27 '17 at 12:31
  • Maybe you can provide me just both :D I kept the question simple for others . I will decide afterwards which fits best :D – Spektakulatius Jul 27 '17 at 12:32
  • Here's the dirty answer: Class s; public Child(Class s) { this.s = s; } private T getInstance() { return s.newInstance(); } – Ahmad Sanie Jul 27 '17 at 12:33
  • for a cleaner one, post details about the problem that you are trying to solve – Ahmad Sanie Jul 27 '17 at 12:33
  • I thought of something like: Class clazz = (Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; – Spektakulatius Jul 27 '17 at 12:37
  • @HovercraftFullOfEels i am not sure if incorrect code does actually exist. Bad programmed one for sure. But if it works and fits the needs it's not incorrect. – Spektakulatius Jul 27 '17 at 12:38
  • 2
    _"Without any arguments"_ Why do you have that requirement? Passing an instance of `T` to the super constructor is by far the cleanest solution I can think of. – Jorn Vernee Jul 27 '17 at 12:41
  • Engineering == Trying new ways! – Spektakulatius Jul 27 '17 at 12:51
  • See also: [Why can't you create an instance of a generic type using “new” operator?](https://stackoverflow.com/questions/30646486/why-cant-you-create-an-instance-of-a-generic-type-using-new-operator) – Jesper Jul 27 '17 at 13:17
  • This has nothing to do with the marked question. – Spektakulatius Jul 27 '17 at 13:51
  • Well, you've figured it out yourself. I was thinking about private inner interface with single parameterless method returning T, then analyzing type returned from that method with reflection to obtain Class without passing it to the constructor. Once you have instance of Class Bob's your uncle. – Filip Malczak Jul 27 '17 at 15:32

3 Answers3

5

The generic information will be erased at compile time, so there will be no T anymore during runtime (you loose the information). Thats why you somewhere will need a Class<> to store the information.


The most clean & simple solution form my point of view is to pass in the class to to the constructor. I know you requested it to be without any constructor argument, but I do not think this is possible.


Code Sample

public abstract class AbstractBase<T> {

    private final T genericTypeObject;

    protected Base(Class<T> type){
        try {
            genericTypeObject = type.newInstance();
        } catch (InstantiationException e) {
            // Handle
        } catch (IllegalAccessException e) {
            // Handle
        }
    }
}

public class Child extends Base<SomeClass> {

    public Child () {
        super(SomeClass.class);
    }
}

Alternative Solution

Using a Supplier (thanks for the comment @Jorn Vernee):

public abstract class AbstractBase<T> {

  private final T genericTypeObject;

  public AbstractBase(Supplier<T> supplier) {
    genericTypeObject = supplier.get();
  }
}

public class Child extends AbstractBase<SomeClass> {

  public Child() {
    super(SomeClass::new);
  }
}
JDC
  • 3,821
  • 2
  • 26
  • 64
  • 1
    Instead of this, I would suggest passing a constructor [reference](https://stackoverflow.com/documentation/java/91/lambda-expressions/5080), since it doesn't throw any exceptions. – Jorn Vernee Jul 27 '17 at 12:57
  • Thank you, added your suggestion. – JDC Jul 27 '17 at 13:08
  • The erasing part may be right in the case i do not have a class, wehere the generic type is extended from something. Maybe my questionw as to simplified. – Spektakulatius Jul 27 '17 at 13:32
0

You must have access to the class to create an instance, so creating an instance without an argument is not possible. You must pass a Class<T>.

UPDATE:

See @JDC's answer.

Maurice Perry
  • 7,501
  • 2
  • 9
  • 19
0

At runtime this returns me a Class instance:

public static Class<?> getGenericClassOfType(Object object){
        Class<?> clazz = (Class<?>) ((ParameterizedType) object.getClass() .getGenericSuperclass()).getActualTypeArguments()[0];
        return clazz;
}

and afterwards I can initiate it with:

public static <T> T getDefaultInstance(Class<T> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
    T instance = null;
    Constructor<T>[] constructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
    Constructor<T> constructor = null;
    for (Constructor cstr : constructors) {
        //Only if default constructor
        if (cstr.getParameters().length == 0) {
            constructor = (Constructor<T>) cstr;
            break;
        }
    }
    if (constructor != null) {
        constructor.setAccessible(true);
        instance = constructor.newInstance();
    }

    return instance;
}

so the code in my base constructor looks like:

public abstract class BaseScene<T extends SceneController> {
    private final static Logger LOGGER =  LogManager.getLogger(BaseScene.class);

    private final T sceneController;

    //public T getSceneController() {
    //    return sceneController;
    //}

    protected BaseScene(){
        T newInstance = null;
        try {
            Class<T> clazz = (Class<T>)ReflectionHelper.getGenericClassOfType(this);
            newInstance = ReflectionHelper.getDefaultInstance(clazz);
        } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
            LOGGER.error("Error while trying to initiate BaseScene",e);
        }
        sceneController = newInstance;
    }
}

which works perfectly as I tested it.

Spektakulatius
  • 2,195
  • 1
  • 21
  • 37