Create instance of generic type in Java?

2018-12-31 01:13发布

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.

标签: java generics
24条回答
泪湿衣
2楼-- · 2018-12-31 01:49

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.

查看更多
何处买醉
3楼-- · 2018-12-31 01:49

Java unfortunatly does not allow what you want to do. See http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createObjects

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);
查看更多
回忆,回不去的记忆
4楼-- · 2018-12-31 01:50

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.

查看更多
栀子花@的思念
5楼-- · 2018-12-31 01:51

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);
查看更多
路过你的时光
6楼-- · 2018-12-31 01:52

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();
}
查看更多
公子世无双
7楼-- · 2018-12-31 01:52

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();
查看更多
登录 后发表回答