Chris Dutrow
Chris Dutrow

Reputation: 50362

Getting class Type information for Elements on a collection

I would like to get gain access to the type of Object held in a Collection. Below is a simplified example of when and why I might want to do this. Is this even possible?

List<Address> addressList = new LinkedList<Address>();

Main.addElement(addressList);

Class Main{
   public void addElement(Object inArgument){
      List<Object> argument = (List<Object>)inArgument;
      argument.add( /* WOULD LIKE TO CREATE A NEW OBJECT OF THE APPROPRIATE TYPE
                       HERE, IN THIS CASE, IT WOULD BE OF TYPE: "Address" */ );
   }
}

Upvotes: 0

Views: 2370

Answers (4)

mdma
mdma

Reputation: 57707

It's not possible to do this with the way your current method is defined, since generics details are not available at runtime. An alternative is to do this:

public <T> void addElement(List<T> inArgument, Class<? extends T> clazz){
   T t = clazz.newInstnace();
   inArgument.add(t);
   // exception handling omitted for brevity
}

You then call addElement like this

addElement(addressList, Address.class);

See the JLS for details on generic types, and type erasure. In nutshell, type erasure is responsbible for this behaviour:

Vector<String> x = new Vector<String>(); 
Vector<Integer> y = new Vector<Integer>(); 
boolean b = x.getClass() == y.getClass();

Results in b==true.

See

Upvotes: 3

emory
emory

Reputation: 10891

I am not sure I understand your question, but I think the "super" keywords might be useful here.

List<Address> addressList = new LinkedList<Address>();
List<Object> stuffToSeeInWashington = new LinkedList<Object>();

Main.addWhiteHouse(addressList);
Main.addWhiteHouse(stuffToSeeInWashington);

Class Main{
   public void addWhiteHouse(List<? super Address> argument){
      Address whiteHouse = new Address("1600 Pennsylvania Ave");
      argument.add( whiteHouse ) ;
   }
}

Upvotes: 0

newacct
newacct

Reputation: 122449

argument.add( null );

null is a value of every reference type :P

But seriously, I don't know why you would want to do this. It implies that there is some kind of "default" value for your type, which is not true for types in general.

Upvotes: 0

erickson
erickson

Reputation: 269697

No, you can't do that with the current implementation of Java's generics. Type parameters are "erased" at compilation time.

You can, via reflection, determine type parameter information for method parameters and return types, and for member variables, but that won't help in this case.

As a practical workaround, most APIs that want to do something similar take a Class instance as a second parameter. For example:

public void addElement(Collection<T> c, Class<? extends T> clz) 
  throws Exception
{
  Constructor<? extends T> ctor = clz.getConstructor();
  T el = ctor.newInstance();
  c.add(el);
}

Upvotes: 5

Related Questions