开发者

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&l开发者_C百科t;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" */ );
   }
}


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


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

  • JLS: Generic Classes and Type Parameters
  • JLS: Type variables


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.


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜