Невозможно создать типичный тип данных в классе

У меня есть неизменяемый класс со следующим расположением,

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 в мой список.

Ответы

Ответ 1

В java-языке генерические средства реализуются путем стирания, поэтому невозможно создать экземпляр типового типа. Также невозможно вызвать массив общего типа и т.д.

Как я могу это преодолеть? Я хочу добавить новую копию аргумента который передается в addData в мой список.

Вы можете попробовать использовать интерфейс Cloneable как привязку типа или добавить свой собственный аналогичный интерфейс.

Ответ 2

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

Ответ 3

В Java 8 вы можете передать lambda factory, которая создаст новый экземпляр требуемого типа:

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

В качестве оболочки для обратного вызова может использоваться встроенный аргумент no-argument Supplier.

Ответ 4

Вы можете использовать метод 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;
    }
    .........
}

Ответ 5

Я искал решение подобной проблемы. Вот решение, которое я сделал:

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

}

Надеюсь, это поможет кому-то.

Ответ 6

вы можете получить тип работы T

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

тогда получите экземпляр T do

type.getClass().newInstance();

Полный пример

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