24

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 . Now , I think this is related to maybe type erasure in Java.

How can I overcome this ? I want to add a new copy of the argument that is being passed to addData into my list.

2
  • 1
    possible duplicate of How to obtain class instance generic argument type Commented Aug 23, 2012 at 14:10
  • Objects are created at Runtime. So we need proper byte code at run time. at max Java erasure can do convert T newT = new T(); to Object newT = new Object() to be available on runtime. But that also wrong since T can be anything extends Object not only Object. Hence compiler error. Commented Jun 8, 2016 at 14:58

6 Answers 6

8
T newT = (T) t.getClass().newInstance() // assuming zero args constructor and you'll // have to catch some reflection exceptions 
Sign up to request clarification or add additional context in comments.

3 Comments

I used this , T was Integer in my class , it threw exceptions at runtime.
@sTEAK.: so if you could do new T(), what would it mean when T is Integer anyway?
At complile time T is replaced by Object
5

In Java 8 you can pass a factory lambda which would create a new instance of the desired type:

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.

3 Comments

This should be the way to go, without workarounds and/or assumptions...
Should be the accepted answer. I am not pro in Java but I guess explicit type casting is rarely a good sign... What do the pros say ?
Hello, great solution! I came up with a doubt, hoping you could share some light, why do I need to create a new A just because it is declared as final? Or is it a best practice to create a new class?
1

In java language generics are implemented by erasure, so it is impossible to instantiate a generic type. 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.

You can try to use Cloneable interface as a type bound or add your own similar interface.

5 Comments

Cloneable as type bound is completely useless
Unless it is used right and clone() is implemented, I suppose.
in order to call a method on an expression, the static type of the expression must have this method
So T extends Object & Cloneable would be more applicable. Nice addition, I did not notice that.
everything automatically extends Object. That doesn't matter. Object's clone is not public and is only meant for a subclass to use to call the super implementation. There is no abstract type that specifies a public clone method in Java.
1

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.

Comments

0

You can use clone() method like this:

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 Comments

Assume my T is Date , and I do Date d = new Date(); A a = new A(); a.addData(d); d.setDate(10); , then will the value in the List be changed or not ?\
Yes, you call a setter of a mutable object you added into the list so you change also the value in the list.
Okay . That was the main purpose behind creating a new copy of the data that was to be inserted. But turns out it doesn't work.
if you make myList.add(d.clone()) and then call d.setX() this will not change the value into the list
@jolivier The idea is nice. But I think the clone method won't work on a generic.
0

you can get the type of T doing

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

then get an instance of T doing

type.getClass().newInstance(); 

Complete example

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.