22

我有一个不可变的类,具有以下布局,

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

我在这里得到的错误是cannot instantiate type T. 现在,我认为这可能type erasure与Java有关。

我该如何克服呢?我想将传递给 addData 的参数的新副本添加到我的列表中。

4

6 回答 6

8
T newT = (T) t.getClass().newInstance() // assuming zero args constructor and you'll
                                        // have to catch some reflection exceptions
于 2012-08-23T14:22:23.040 回答
5

在 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;
    }
    .........
}

例如像这样使用它:

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

内置的无参数供应商接口可以用作回调的包装器。

于 2017-09-27T09:20:15.963 回答
1

在java语言中泛型是通过擦除来实现的,所以不可能实例化一个泛型类型。也不可能创建一个泛型类型的数组等等。

我该如何克服呢?我想将传递给 addData 的参数的新副本添加到我的列表中。

您可以尝试使用Cloneable接口作为类型绑定或添加自己的类似接口。

于 2012-08-23T14:09:45.380 回答
1

我寻找类似问题的解决方案。这是我提出的解决方案:

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

}

希望这会对某人有所帮助。

于 2015-01-03T21:46:15.353 回答
0

您可以像这样使用 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;
    }
    .........
}
于 2012-08-23T14:15:29.320 回答
-1

你可以得到 T 的类型

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

然后得到一个 T 的实例

type.getClass().newInstance();

完整示例

public T foo() {
    try {
        return (T) type.getClass().newInstance();
    } catch (Exception e) {
        return null;
    }
}
于 2014-01-07T14:14:09.770 回答