604

Is it possible to create an instance of a generic type in Java? I'm thinking based on what I've seen that the answer is no (due to type erasure), but I'd be interested if anyone can see something I'm missing:

class SomeContainer<E>
{
    E createContents()
    {
        return what???
    }
}

EDIT: It turns out that Super Type Tokens could be used to resolve my issue, but it requires a lot of reflection-based code, as some of the answers below have indicated.

I'll leave this open for a little while to see if anyone comes up with anything dramatically different than Ian Robertson's Artima Article.

John Woo
  • 238,432
  • 61
  • 456
  • 464
David Citron
  • 41,009
  • 18
  • 60
  • 71
  • 2
    Just tested performance on Android device. 10000 operations and: 8-9 ms takes new SomeClass(), 9-11 ms takes Factory.createInstance() and 64-71 ms takes shortest reflection: SomeClass z = SomeClass.class.newInstance(). And all tests were in single try-catch block. Reflection newInstance() throws 4 different exceptions, remember? So I decided to use factory pattern – Deepscorn May 15 '14 at 19:38
  • See also: http://stackoverflow.com/a/5684761/59087 – Dave Jarvis Mar 04 '15 at 02:22
  • 4
    With Java 8, you now can pass a constructor reference or a lambda which makes this problem pretty trivial to work around. See [my answer below](http://stackoverflow.com/a/36315051/128397) for details. – Daniel Pryden Mar 30 '16 at 16:54
  • I think this is bad idea to write such code, the are more elegant and readable ways of solving the underneath problem. – Krzysztof Cichocki Mar 21 '17 at 11:53
  • 1
    @DavidCitron *"for a little while"* he said... It has been eleven years since then... – MC Emperor Aug 21 '19 at 18:55

28 Answers28

351

You are correct. You can't do new E(). But you can change it to

private static class SomeContainer<E> {
    E createContents(Class<E> clazz) {
        return clazz.newInstance();
    }
}

It's a pain. But it works. Wrapping it in the factory pattern makes it a little more tolerable.

Lii
  • 9,906
  • 6
  • 53
  • 73
Justin Rudd
  • 5,036
  • 4
  • 20
  • 16
  • 13
    Yeah, I saw that solution, but it only works if you already have a reference to a Class object of the type that you want to instantiate. – David Citron Sep 16 '08 at 18:14
  • 11
    Yeah I know. It would be nice if you could do E.class but that simply gives you Object.class because of erasure :) – Justin Rudd Sep 16 '08 at 18:43
  • 6
    That's the correct approach for this problem. It's usually not what you wish, but it's what you get. – Joachim Sauer Dec 17 '08 at 22:13
  • Yeah, best solution short of switching to Dependency Injection or writing factories. – Joseph Lust Jun 13 '12 at 18:24
  • 46
    And how do you call the createContents() method? – Alexis Dufrenoy Aug 11 '12 at 21:36
  • @Traroth, I think you should just create a new instance of the class and call the method with an existing object of the type you want. For example: `new SomeContainer("Test");`. – Sam Oct 19 '12 at 10:12
  • 3
    @Alexis Dufrenoy - bit late but for completeness... `sc = new SomeContainer(); sc.createContents(String.class);`. For what it's worth, as far as I can see, this is the only answer that would work for the OP. I've played with the others but get `ClassCastException`s converting from `Type` to `Class` or can only see `` from inside the parameterised class itself. Interested to know if others have concrete finidings though. +1 to this and will hold fire on my downvotes on the others... Am I missing something? – wmorrison365 Apr 10 '14 at 11:14
  • 9
    **This is no longer the only way to do this, there is a better way now that doesn't require passing in a `Class>` reference using Guava and TypeToken, [see this answer for the code and links!](http://stackoverflow.com/a/25195050/177800)** –  Aug 08 '14 at 02:09
  • i was going to do this in a factory class. my super class has a generic type passed to it on instatiation MyClass

    . subclass is passed a concrete type in the <> brackets. then i can pass the generic type to my Factory and cretae any presenter type in theory. going to play around with it this evening

    – filthy_wizard Jun 10 '16 at 15:46
  • @wmorrison365 : And how will this solution work if the type that I want to instantiate requires parameters in its constructor? This approach only seems to work with no-arg constructor types... – Manish Kumar Sharma May 19 '17 at 09:08
  • Hi @pulp-fiction, you would have to go through the constructor on the `Class` instance itself - using `Class#getDeclaredConstructor` and call it using `Constructor#newInstance`. For example: (1) get constructor from Class: `Constructor extends E> constructor = clazz.getDeclaredConstructor(new Class[] { String.class, String.class, boolean.class, long.class});` (2) then call parameterised constructor - values would need to be obtained `instance = constructor.newInstance(aString, anotherString, aBool, aLong);` – wmorrison365 May 22 '17 at 11:26
  • Thanks, @JustinRudd ! Why doesn't type erasure apply to `Class clazz`, so it becomes `Class clazz`, and then `clazz.newInstance()` returns an instance of `Object`? – Tim Jan 29 '18 at 17:09
  • @Tim that’s not how type erasure works. It doesn’t turn `Class` into `Class`, which would still be a generic type. Type erasure turns `Class` into `Class`, but that still is the same `Class` object at runtime, representing the same actual class. Just like it worked before Generics, e.g. `String.class.newInstance()` always returns an instance of `String`, but before Generics, the compiler would not know it and tell you that you have to cast the returned reference of type `Object` to `String`. But casting a reference type doesn’t change the actual type of the object. – Holger Jan 10 '19 at 08:56
  • 1
    this solution worked, however actually it is marked as deprecated. and it should to be replaced by: clazz.getDeclaredConstructor().newInstance() – eriknyk Apr 17 '20 at 16:58
135

I don't know if this helps, but when you subclass (including anonymously) a generic type, the type information is available via reflection. e.g.,

public abstract class Foo<E> {

  public E instance;  

  public Foo() throws Exception {
    instance = ((Class)((ParameterizedType)this.getClass().
       getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
    ...
  }

}

So, when you subclass Foo, you get an instance of Bar e.g.,

// notice that this in anonymous subclass of Foo
assert( new Foo<Bar>() {}.instance instanceof Bar );

But it's a lot of work, and only works for subclasses. Can be handy though.

peterh
  • 9,698
  • 15
  • 68
  • 87
noah
  • 20,296
  • 17
  • 59
  • 84
  • 2
    Yes, this is nice especially if the generic class is abstract, you can do this in the concrete subclasses :) – Pierre Henry Apr 18 '13 at 14:36
  • This method also works if class `Foo` isn't abstract. But why does it only work on anonymous subclasses of Foo? Suppose we make `Foo` concrete (we leave out `abstract`), why will `new Foo();` result in an error, while `new Foo(){};` doesn't? (Exception: "Class cannot be cast to ParameterizedType") – Tim Kuipers Dec 22 '13 at 14:52
  • 3
    @TimKuipers The `` in `class Foo` is not bound to any particular type. You will see the exceptional behavior whenever `E` is not *statically* bound, as in: `new Foo()`, `new Foo() {...}`, or `class Fizz extends Foo`. The first case isn't statically bound, it is *erased* at compile time. The second case substitutes another type variable (T) in place of `E` but is still unbound. And in the last case it should be obvious that `E` is still unbound. – William Price Apr 25 '14 at 04:27
  • 5
    An example of statically binding the type parameter would be `class Fizz extends Foo` -- in this case, users of `Fizz` get something that is a `Foo` and cannot be anything but a `Foo`. So in this case, the compiler is happy to encode that information into the class metadata for `Fizz` and make it available as a `ParameterizedType` to reflection code. When you create an anonymous inner class like `new Foo() {...}` it is doing the same thing, except instead of `Fizz` the compiler generates an "anonymous" class name that you won't know until the outer class is compiled. – William Price Apr 25 '14 at 04:32
  • 4
    It should be noted that this won't work if the type arguments are also a ParameterizedType. For example, `Foo>`. You'll be creating an instance of `ParameterizedTypeImpl` which can't be explicitly created. Therefore, it is a good idea to check if `getActualTypeArguments()[0]` is returning a `ParameterizedType`. If it is, then you want to get the raw type, and create an instance of that instead. – crush Aug 20 '14 at 15:42
  • Why can I not use `getGenericSuperclass()` directly in the code then? – Tomáš Zato - Reinstate Monica May 01 '15 at 02:40
  • @WilliamPrice and it’s important to emphasize that it does not work when the type does not get fixed by the subclass, e.g. `class Fizz extends Foo { … }`, so it’s a fragile construct as the base class can not declare the requirements on the form of the subclass. – Holger Jan 10 '19 at 09:01
  • @Holger I thought I had in my first comment – William Price Jan 10 '19 at 13:41
  • @WilliamPrice right, I’ve read your second comment, but anyway, we both *said* it in a comment, but that point should be *emphasized* in the answer. – Holger Jan 10 '19 at 14:08
129

In Java 8 you can use the Supplier functional interface to achieve this pretty easily:

class SomeContainer<E> {
  private Supplier<E> supplier;

  SomeContainer(Supplier<E> supplier) {
    this.supplier = supplier;
  }

  E createContents() {
    return supplier.get();
  }
}

You would construct this class like this:

SomeContainer<String> stringContainer = new SomeContainer<>(String::new);

The syntax String::new on that line is a constructor reference.

If your constructor takes arguments you can use a lambda expression instead:

SomeContainer<BigInteger> bigIntegerContainer
    = new SomeContainer<>(() -> new BigInteger(1));
Daniel Pryden
  • 54,536
  • 12
  • 88
  • 131
  • 7
    Good one. It avoids reflection and having to treat exceptions. – Bruno Leite Jun 07 '17 at 16:14
  • 2
    So nice. Unfortunately for Android users, this requires API level 24 or higher. – Michael Updike Jan 23 '18 at 08:43
  • 2
    …and it’s not different to [this even older answer](https://stackoverflow.com/a/75528/2711488) showing that the technical pattern behind it is even older than Java’s support for lambda expressions and method references while you can even use that older code with them once you upgraded your compiler… – Holger Jan 10 '19 at 09:05
  • Would it be possible to put just `SomeContainer stringContainer = new SomeContainer(String::new);`? – Aaron Franke Jan 22 '19 at 02:03
  • @AaronFranke: No, because then you'd be using a [raw type](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). – Daniel Pryden Jan 22 '19 at 13:36
88

You'll need some kind of abstract factory of one sort or another to pass the buck to:

interface Factory<E> {
    E create();
}

class SomeContainer<E> {
    private final Factory<E> factory;
    SomeContainer(Factory<E> factory) {
        this.factory = factory;
    }
    E createContents() {
        return factory.create();
    }
}
Tom Hawtin - tackline
  • 139,906
  • 30
  • 206
  • 293
  • ..and how Factory.create() looks like? – OhadR Jan 27 '16 at 12:43
  • 6
    @OhadR `Factory<>` is an interface and so there's no body. The point is you need a layer of indirections to pass the buck to methods that do "know" the required code to construct an instance. It's much better to do this with normal code rather than metalinguistic `Class` or `Constructor` as reflection brings a whole world of hurt. – Tom Hawtin - tackline Jan 27 '16 at 17:29
  • 2
    Now days you can create a factory instance with a method reference expression like this: `SomeContainer cont = new SomeContainer<>(SomeElement::new);` – Lii Apr 07 '18 at 11:31
26
package org.foo.com;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Basically the same answer as noah's.
 */
public class Home<E>
{

    @SuppressWarnings ("unchecked")
    public Class<E> getTypeParameterClass()
    {
        Type type = getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        return (Class<E>) paramType.getActualTypeArguments()[0];
    }

    private static class StringHome extends Home<String>
    {
    }

    private static class StringBuilderHome extends Home<StringBuilder>
    {
    }

    private static class StringBufferHome extends Home<StringBuffer>
    {
    }   

    /**
     * This prints "String", "StringBuilder" and "StringBuffer"
     */
    public static void main(String[] args) throws InstantiationException, IllegalAccessException
    {
        Object object0 = new StringHome().getTypeParameterClass().newInstance();
        Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
        Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
        System.out.println(object0.getClass().getSimpleName());
        System.out.println(object1.getClass().getSimpleName());
        System.out.println(object2.getClass().getSimpleName());
    }

}
Lars Bohl
  • 953
  • 13
  • 20
  • 3
    Good approach by this code may cause ClassCastException if You use in the generic a generic type. Then You retrive the actualType argument You should check that it is also ParamterizedType and if so return his RawType (or something better than this). Another issue with this is when we extend more then once this code also will throw the ClassCastExeption. – Damian Leszczyński - Vash Sep 10 '10 at 10:44
  • 3
    Caused by: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class – juan Dec 04 '12 at 14:45
  • @DamianLeszczyński-Vash will also fail with, e.g. `class GenericHome extends Home{}` – Holger Jan 10 '19 at 09:09
24

If you need a new instance of a type argument inside a generic class then make your constructors demand its class...

public final class Foo<T> {

    private Class<T> typeArgumentClass;

    public Foo(Class<T> typeArgumentClass) {

        this.typeArgumentClass = typeArgumentClass;
    }

    public void doSomethingThatRequiresNewT() throws Exception {

        T myNewT = typeArgumentClass.newInstance();
        ...
    }
}

Usage:

Foo<Bar> barFoo = new Foo<Bar>(Bar.class);
Foo<Etc> etcFoo = new Foo<Etc>(Etc.class);

Pros:

  • Much simpler (and less problematic) than Robertson's Super Type Token (STT) approach.
  • Much more efficient than the STT approach (which will eat your cellphone for breakfast).

Cons:

  • Can't pass Class to a default constructor (which is why Foo is final). If you really do need a default constructor you can always add a setter method but then you must remember to give her a call later.
  • Robertson's objection... More Bars than a black sheep (although specifying the type argument class one more time won't exactly kill you). And contrary to Robertson's claims this does not violate the DRY principal anyway because the compiler will ensure type correctness.
  • Not entirely Foo<L>proof. For starters... newInstance() will throw a wobbler if the type argument class does not have a default constructor. This does apply to all known solutions though anyway.
  • Lacks the total encapsulation of the STT approach. Not a big deal though (considering the outrageous performance overhead of STT).
R2D2M2
  • 261
  • 2
  • 4
23

You can do this now and it doesn't require a bunch of reflection code.

import com.google.common.reflect.TypeToken;

public class Q26289147
{
    public static void main(final String[] args) throws IllegalAccessException, InstantiationException
    {
        final StrawManParameterizedClass<String> smpc = new StrawManParameterizedClass<String>() {};
        final String string = (String) smpc.type.getRawType().newInstance();
        System.out.format("string = \"%s\"",string);
    }

    static abstract class StrawManParameterizedClass<T>
    {
        final TypeToken<T> type = new TypeToken<T>(getClass()) {};
    }
}

Of course if you need to call the constructor that will require some reflection, but that is very well documented, this trick isn't!

Here is the JavaDoc for TypeToken.

Lukasz Stelmach
  • 4,821
  • 3
  • 22
  • 29
  • 6
    This solution works for a limited set of cases, just like @noah's answer with reflection. I tried them all today... And I ended at passing an instance of the parameter class to the parameterized class (in order to be able to call .newInstance() ). Very big deficiency of "generics"... new Foo(Bar.class); ... class Foo { private final Class mTFactory; Foo(Class tClass) { mTFactory = tClass; ... } T instance = tFactory.newInstance(); } – yvolk Mar 01 '15 at 19:36
  • this works in all cases, even static factory methods that take generic parameters –  Feb 18 '16 at 22:35
14

Think about a more functional approach: instead of creating some E out of nothing (which is clearly a code smell), pass a function that knows how to create one, i.e.

E createContents(Callable<E> makeone) {
     return makeone.call(); // most simple case clearly not that useful
}
Ingo
  • 34,949
  • 5
  • 49
  • 97
13

From Java Tutorial - Restrictions on Generics:

Cannot Create Instances of Type Parameters

You cannot create an instance of a type parameter. For example, the following code causes a compile-time error:

public static <E> void append(List<E> list) {
    E elem = new E();  // compile-time error
    list.add(elem);
}

As a workaround, you can create an object of a type parameter through reflection:

public static <E> void append(List<E> list, Class<E> cls) throws Exception {
    E elem = cls.newInstance();   // OK
    list.add(elem);
}

You can invoke the append method as follows:

List<String> ls = new ArrayList<>();
append(ls, String.class);
Sergiy Sokolenko
  • 5,398
  • 31
  • 35
7

Here is an option I came up with, it may help:

public static class Container<E> {
    private Class<E> clazz;

    public Container(Class<E> clazz) {
        this.clazz = clazz;
    }

    public E createContents() throws Exception {
        return clazz.newInstance();
    }
}

EDIT: Alternatively you can use this constructor (but it requires an instance of E):

@SuppressWarnings("unchecked")
public Container(E instance) {
    this.clazz = (Class<E>) instance.getClass();
}
Mike Stone
  • 42,897
  • 27
  • 110
  • 137
  • Yeah, this works the same even without generics--with generics the instantiation of this container becomes a bit redundant (you have to specify what "E" is twice). – David Citron Sep 16 '08 at 18:17
  • well, that's what happens when you use Java and generics... they aren't pretty, and there are severe limitations... – Mike Stone Sep 16 '08 at 18:20
7

If you want not to type class name twice during instantiation like in:

new SomeContainer<SomeType>(SomeType.class);

You can use factory method:

<E> SomeContainer<E> createContainer(Class<E> class); 

Like in:

public class Container<E> {

    public static <E> Container<E> create(Class<E> c) {
        return new Container<E>(c);
    }

    Class<E> c;

    public Container(Class<E> c) {
        super();
        this.c = c;
    }

    public E createInstance()
            throws InstantiationException,
            IllegalAccessException {
        return c.newInstance();
    }

}
jb.
  • 20,419
  • 16
  • 91
  • 130
6

When you are working with E at compile time you don't really care the actual generic type "E" (either you use reflection or work with base class of generic type) so let the subclass provide instance of E.

abstract class SomeContainer<E>
{
    abstract protected E createContents();
    public void doWork(){
        E obj = createContents();
        // Do the work with E 
     }
}

class BlackContainer extends SomeContainer<Black>{
    protected Black createContents() {
        return new Black();
    }
}
zemiak
  • 92
  • 4
Ira
  • 618
  • 8
  • 7
6

Java unfortunatly does not allow what you want to do. See the official workaround :

You cannot create an instance of a type parameter. For example, the following code causes a compile-time error:

public static <E> void append(List<E> list) {
    E elem = new E();  // compile-time error
    list.add(elem);
}

As a workaround, you can create an object of a type parameter through reflection:

public static <E> void append(List<E> list, Class<E> cls) throws Exception {
    E elem = cls.newInstance();   // OK
    list.add(elem);
}

You can invoke the append method as follows:

List<String> ls = new ArrayList<>();
append(ls, String.class);
ETO
  • 5,848
  • 1
  • 15
  • 35
Neepsnikeep
  • 179
  • 2
  • 11
  • Could you please tell me why you're downvoting when you do so? I don't see why the official workaround is a bad solution. Thanks. – Neepsnikeep Aug 30 '17 at 06:59
  • 3
    I guess you get down votes, because your answer is essentially the same as Justin Rudd's: https://stackoverflow.com/a/75254/103412 – Torsten Mar 18 '19 at 10:37
5

You can use:

Class.forName(String).getConstructor(arguments types).newInstance(arguments)

But you need to supply the exact class name, including packages, eg. java.io.FileInputStream. I used this to create a math expressions parser.

hichris123
  • 9,735
  • 15
  • 51
  • 66
  • 15
    And how do you get the exact class name of the generic type at runtime? – David Citron Dec 23 '08 at 08:05
  • You'd have to save it using an instance of that class. Doable, though hardly convenient. If your generic had a member of type E (or T or whatever), getting it's binary name is just `foo.getClass().getName()`. Where does THAT instance comes from? I'm currently passing one into a constructor in the project I'm now working on. – Mark Storer Aug 16 '19 at 13:36
5

Hope this's not too late to help!!!

Java is type-safe, meaning that only Objects are able to create instances.

In my case I cannot pass parameters to the createContents method. My solution is using extends unlike the answer below.

private static class SomeContainer<E extends Object> {
    E e;
    E createContents() throws Exception{
        return (E) e.getClass().getDeclaredConstructor().newInstance();
    }
}

This is my example case in which I can't pass parameters.

public class SomeContainer<E extends Object> {
    E object;

    void resetObject throws Exception{
        object = (E) object.getClass().getDeclaredConstructor().newInstance();
    }
}

Using reflection create run time error, if you extends your generic class with none object type. To extends your generic type to object convert this error to compile time error.

Daniel Methner
  • 330
  • 3
  • 15
Se Song
  • 1,393
  • 2
  • 17
  • 30
4

Use the TypeToken<T> class:

public class MyClass<T> {
    public T doSomething() {
        return (T) new TypeToken<T>(){}.getRawType().newInstance();
    }
}
Tobias Tengler
  • 4,101
  • 2
  • 16
  • 32
cacheoff
  • 61
  • 3
3

I thought I could do that, but quite disappointed: it doesn't work, but I think it still worths sharing.

Maybe someone can correct:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface SomeContainer<E> {
    E createContents();
}

public class Main {

    @SuppressWarnings("unchecked")
    public static <E> SomeContainer<E> createSomeContainer() {
        return (SomeContainer<E>) Proxy.newProxyInstance(Main.class.getClassLoader(),
                new Class[]{ SomeContainer.class }, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Class<?> returnType = method.getReturnType();
                return returnType.newInstance();
            }
        });
    }

    public static void main(String[] args) {
        SomeContainer<String> container = createSomeContainer();

    [*] System.out.println("String created: [" +container.createContents()+"]");

    }
}

It produces:

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
    at Main.main(Main.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Line 26 is the one with the [*].

The only viable solution is the one by @JustinRudd

Luigi R. Viggiano
  • 8,103
  • 6
  • 46
  • 60
3

An imporovement of @Noah's answer.

Reason for Change

a] Is safer if more then 1 generic type is used in case you changed the order.

b] A class generic type signature changes from time to time so that you will not be surprised by unexplained exceptions in the runtime.

Robust Code

public abstract class Clazz<P extends Params, M extends Model> {

    protected M model;

    protected void createModel() {
    Type[] typeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
    for (Type type : typeArguments) {
        if ((type instanceof Class) && (Model.class.isAssignableFrom((Class) type))) {
            try {
                model = ((Class<M>) type).newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

Or use the one liner

One Line Code

model = ((Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();
Amio.io
  • 17,083
  • 11
  • 66
  • 100
3

what you can do is -

  1. First declare the variable of that generic class

    2.Then make a constructor of it and instantiate that object

  2. Then use it wherever you want to use it

example-

1

private Class<E> entity;

2

public xyzservice(Class<E> entity) {
        this.entity = entity;
    }



public E getEntity(Class<E> entity) throws InstantiationException, IllegalAccessException {
        return entity.newInstance();
    }

3.

E e = getEntity(entity);

Sudhanshu Jain
  • 1,681
  • 1
  • 6
  • 4
  • 1
    return entity.newInstance(); triggers a warning: "The method newInstance() from the type Class is deprecated since version 9" – Daniel Methner Nov 16 '20 at 06:16
0

You can achieve this with the following snippet:

import java.lang.reflect.ParameterizedType;

public class SomeContainer<E> {
   E createContents() throws InstantiationException, IllegalAccessException {
      ParameterizedType genericSuperclass = (ParameterizedType)
         getClass().getGenericSuperclass();
      @SuppressWarnings("unchecked")
      Class<E> clazz = (Class<E>)
         genericSuperclass.getActualTypeArguments()[0];
      return clazz.newInstance();
   }
   public static void main( String[] args ) throws Throwable {
      SomeContainer< Long > scl = new SomeContainer<>();
      Long l = scl.createContents();
      System.out.println( l );
   }
}
Aubin
  • 13,790
  • 8
  • 55
  • 78
Bogdan Veliscu
  • 436
  • 5
  • 9
  • 4
    Totally wrong: Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType – Aubin Jan 03 '13 at 19:51
0

There are various libraries that can resolve E for you using techniques similar to what the Robertson article discussed. Here's an implemenation of createContents that uses TypeTools to resolve the raw class represented by E:

E createContents() throws Exception {
  return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}

This assumes that getClass() resolves to a subclass of SomeContainer and will fail otherwise since the actual parameterized value of E will have been erased at runtime if it's not captured in a subclass.

Jonathan
  • 5,298
  • 33
  • 46
0

Here's an implementation of createContents that uses TypeTools to resolve the raw class represented by E:

E createContents() throws Exception {
  return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}

This approach only works if SomeContainer is subclassed so the actual value of E is captured in a type definition:

class SomeStringContainer extends SomeContainer<String>

Otherwise the value of E is erased at runtime and is not recoverable.

Jonathan
  • 5,298
  • 33
  • 46
0
return   (E)((Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
Rachid
  • 25
  • 1
  • 1
    This does not work in my example in the original question. The superclass for `SomeContainer` is simply `Object`. Therefore, `this.getClass().getGenericSuperclass()` returns a `Class` (class java.lang.Object), not a `ParameterizedType`. This was actually already pointed out by peer answer http://stackoverflow.com/questions/75175/create-instance-of-generic-type-in-java/5389482#75345 as well. – David Citron Jul 09 '11 at 17:54
  • 1
    Totally wrong: Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType – Aubin Jan 03 '13 at 19:56
0

Here is an improved solution, based on ParameterizedType.getActualTypeArguments, already mentioned by @noah, @Lars Bohl, and some others.

First small improvement in the implementation. Factory should not return instance, but a type. As soon as you return instance using Class.newInstance() you reduce a scope of usage. Because only no-arguments constructors can be invoke like this. A better way is to return a type, and allow a client to choose, which constructor he wants to invoke:

public class TypeReference<T> {
  public Class<T> type(){
    try {
      ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
      if (pt.getActualTypeArguments() == null || pt.getActualTypeArguments().length == 0){
        throw new IllegalStateException("Could not define type");
      }
      if (pt.getActualTypeArguments().length != 1){
        throw new IllegalStateException("More than one type has been found");
      }
      Type type = pt.getActualTypeArguments()[0];
      String typeAsString = type.getTypeName();
      return (Class<T>) Class.forName(typeAsString);

    } catch (Exception e){
      throw new IllegalStateException("Could not identify type", e);
    }

  }
}

Here is a usage examples. @Lars Bohl has shown only a signe way to get reified geneneric via extension. @noah only via creating an instance with {}. Here are tests to demonstrate both cases:

import java.lang.reflect.Constructor;

public class TypeReferenceTest {

  private static final String NAME = "Peter";

  private static class Person{
    final String name;

    Person(String name) {
      this.name = name;
    }
  }

  @Test
  public void erased() {
    TypeReference<Person> p = new TypeReference<>();
    Assert.assertNotNull(p);
    try {
      p.type();
      Assert.fail();
    } catch (Exception e){
      Assert.assertEquals("Could not identify type", e.getMessage());
    }
  }

  @Test
  public void reified() throws Exception {
    TypeReference<Person> p = new TypeReference<Person>(){};
    Assert.assertNotNull(p);
    Assert.assertEquals(Person.class.getName(), p.type().getName());
    Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
    Assert.assertNotNull(ctor);
    Person person = (Person) ctor.newInstance(NAME);
    Assert.assertEquals(NAME, person.name);
  }

  static class TypeReferencePerson extends TypeReference<Person>{}

  @Test
  public void reifiedExtenension() throws Exception {
    TypeReference<Person> p = new TypeReferencePerson();
    Assert.assertNotNull(p);
    Assert.assertEquals(Person.class.getName(), p.type().getName());
    Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
    Assert.assertNotNull(ctor);
    Person person = (Person) ctor.newInstance(NAME);
    Assert.assertEquals(NAME, person.name);
  }
}

Note: you can force the clients of TypeReference always use {} when instance is created by making this class abstract: public abstract class TypeReference<T>. I've not done it, only to show erased test case.

Alexandr
  • 8,399
  • 11
  • 54
  • 92
0

Note that a generic type in kotlin could come without a default constructor.

 implementation("org.objenesis","objenesis", "3.2")

    val fooType = Foo::class.java
    var instance: T = try {
        fooType.newInstance()
    } catch (e: InstantiationException) {
//            Use Objenesis because the fooType class has not a default constructor
        val objenesis: Objenesis = ObjenesisStd()
        objenesis.newInstance(fooType)
    }
Braian Coronel
  • 17,823
  • 4
  • 30
  • 33
0

As you said, you can't really do it because of type erasure. You can sort of do it using reflection, but it requires a lot of code and lot of error handling.

Adam Rosenfield
  • 360,316
  • 93
  • 484
  • 571
  • How would you even do it using reflection? The only method I see is Class.getTypeParameters(), but that only returns the declared types, not the run-time types. – David Citron Sep 16 '08 at 18:13
  • Are you talking about this? http://www.artima.com/weblogs/viewpost.jsp?thread=208860 – David Citron Sep 16 '08 at 18:52
0

If you mean new E() then it is impossible. And I would add that it is not always correct - how do you know if E has public no-args constructor? But you can always delegate creation to some other class that knows how to create an instance - it can be Class<E> or your custom code like this

interface Factory<E>{
    E create();
}    

class IntegerFactory implements Factory<Integer>{    
  private static int i = 0; 
  Integer create() {        
    return i++;    
  }
}
Pavel Feldman
  • 4,361
  • 5
  • 28
  • 31
-1

You can with a classloader and the class name, eventually some parameters.

final ClassLoader classLoader = ...
final Class<?> aClass = classLoader.loadClass("java.lang.Integer");
final Constructor<?> constructor = aClass.getConstructor(int.class);
final Object o = constructor.newInstance(123);
System.out.println("o = " + o);
Roald
  • 212
  • 2
  • 3