简体   繁体   English

无法在类中实例化通用数据类型

[英]Cannot instantiate generic data type in class

I have an immutable class , with the following layout , 我有一个不可变的类,具有以下布局,

public final class A <T> {
    private ArrayList<T> myList;
    private A(){
        myList = new ArrayList<T>();
    }
    public A<T> addData(T t){
        A newOb = // make a new list and instantiate using overloaded constructor
        T newT = new T(); ***********ERROR HERE*************
        newOb.myList.add(newT);
        return newOb;
    }
    .........
}

The error that I get here is cannot instantiate type T . 我在这里得到的错误是cannot instantiate type T Now , I think this is related to maybe type erasure in Java. 现在,我认为这与Java中的type erasure有关。

How can I overcome this ? 我怎么能克服这个? I want to add a new copy of the argument that is being passed to addData into my list. 我想添加一个新的参数副本,该副本将传递给我的列表中的addData。

T newT = (T) t.getClass().newInstance() // assuming zero args constructor and you'll
                                        // have to catch some reflection exceptions

In Java 8 you can pass a factory lambda which would create a new instance of the desired type: 在Java 8中,您可以传递工厂lambda ,它将创建所需类型的新实例:

public final class A <T> {
    private ArrayList<T> myList;
    private A(){
        myList = new ArrayList<T>();
    }
    public A<T> addData(Supplier<T> factory){
        A newOb = // make a new list and instantiate using overloaded constructor
        T newT = factory.get();
        newOb.myList.add(newT);
        return newOb;
    }
    .........
}

Use it like this for example: 像这样使用它,例如:

A<Integer> a = new A<>();
a.addData( () -> new Integer(0) );

The built-in no-argument Supplier interface can be used as the wrapper for the callback. 内置的无参数Supplier接口可以用作回调的包装器。

I looked for solution of similar problem. 我寻找类似问题的解决方案。 Here is the solution I made: 这是我做的解决方案:

public final class ImmutableA<T> {
private ArrayList<T> myList;
private Class<T> clazz;

public static <E> ImmutableA<E> createEmpty(Class<E> clazz) {
    return new ImmutableA<>(clazz);
}

private ImmutableA(Class<T> clazz) {
    this.myList = new ArrayList<T>();
    this.clazz = clazz;
}

public ImmutableA<T> addData(T t) {
    ImmutableA<T> newOb = new ImmutableA<>(clazz);
    try {
        Constructor<T> constructor = clazz.getDeclaredConstructor(clazz);
        T newT = constructor.newInstance(t);
        newOb.myList.add(newT);
        return newOb;
    } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

public ArrayList<T> getMyList() {
    return myList;
}

public static void main(String[] args) throws InstantiationException, IllegalAccessException {
    ImmutableA<String> immutableA = createEmpty(String.class);
    System.out.print(immutableA.getMyList().toString());
    immutableA = immutableA.addData("a");
    System.out.print(immutableA.getMyList().toString());
    immutableA = immutableA.addData("b");
    System.out.print(immutableA.getMyList().toString());
    immutableA = immutableA.addData("c");
    System.out.print(immutableA.getMyList().toString());
}

} }

Hope this will help to somebody. 希望这会对某人有所帮助。

In java language generics are implemented by erasure, so it is impossible to instantiate a generic type. 在java语言中,泛型是通过擦除实现的,因此不可能实例化泛型类型。 Also it is impossible to instiate an array of generic type and so on. 此外,也无法通过一般类型的数组来等等。

How can I overcome this ? 我怎么能克服这个? I want to add a new copy of the argument that is being passed to addData into my list. 我想添加一个新的参数副本,该副本将传递给我的列表中的addData。

You can try to use Cloneable interface as a type bound or add your own similar interface. 您可以尝试将Cloneable接口用作类型绑定或添加您自己的类似接口。

You can use clone() method like this: 您可以像这样使用clone()方法:

public final class A <T extends Cloneable> {
    private ArrayList<T> myList;
    private A(){
        myList = new ArrayList<T>();
    }
    public A<T> addData(T t){
        T newT = t.clone();
        newOb.myList.add(newT);
        return newOb;
    }
    .........
}

you can get the type of T doing 你可以得到T的类型

Type type = new TypeToken<T>(){}.getType();

then get an instance of T doing 然后得到一个T做的实例

type.getClass().newInstance();

Complete example 完整的例子

public T foo() {
    try {
        return (T) type.getClass().newInstance();
    } catch (Exception e) {
        return null;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM