views:

53

answers:

4

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" */ );
   }
}
+3  A: 

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

mdma
+5  A: 

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);
}
erickson
Bummer. I guess that makes sense though since the list is just a collection of references. Debatably, the application doesn't need to know the type of Object that the reference points to at runtime.
DutrowLLC
A: 
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.

newacct
A: 

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