Create instances of generic types in Java?

Can instances of generic types be created in Java? I see from what I see is that the answer is thinking no (because of type erasure), but I'm interested if anyone can see what I've lost:

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

Editor: as it turns out, Super type token It can be used to solve my problem, but it requires a lot of reflection based code, as shown in some of the answers below.

I'm going to open this up for a moment to see if anyone has proposed Artima Article Very different thing .

#1 building

You can do this using the following code snippets:

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 );
   }
}

#2 building

from Java Tutorial - Generic restrictions :

Cannot create instance of type parameter

You cannot create an instance of a type parameter. For example, the following code can cause compile time errors:

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

As a workaround, you can create objects of type parameters by reflection:

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

You can call the append method as follows:

List<String> ls = new ArrayList<>();
append(ls, String.class);

#3 building

I thought I could do it, but I was disappointed: it didn't work, but I was still worth 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 has [*].

The only viable solution is the one provided by @ JustinRudd

#4 building

If you need to use a new instance of a type parameter in a generic class, make the constructor need 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);

Advantage:

  • It is much simpler (and less problematic) than Robertson's supertype token (STT) method.
  • It's much more efficient than STT, which eats your phone at breakfast.

Disadvantages:

  • Class cannot be passed to the default constructor (that's why Foo is the ultimate). If you do need a default constructor, you can add a setter method at any time, but remember to call her later.
  • Robertson's objection... Is much more barbell than "scum" (although specifying the type argument class again won't kill you completely). Contrary to Robertson's assertion, this does not violate the DRY body in any case, because the compiler will ensure that the type is correct.
  • Not exactly foo < l > proof. First, if the type argument class does not have a default constructor, newInstance() raises a wiggler. In any case, this does apply to all known solutions.
  • The whole package of STT method is lack. However, it's not a big deal (considering STT's amazing performance overhead).

#5 building

You can use a class loader and a class name, and finally add 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);

Tags: Java less

Posted on Fri, 10 Jan 2020 01:56:36 -0800 by anindya23