I have to ask a question in return: is your GenSet
“checked” or “unchecked”?
What does that mean?
-
Checked: strong typing.
GenSet
knows explicitly what type of objects it contains (i.e. its constructor was explicitly called with aClass<E>
argument, and methods will throw an exception when they are passed arguments that are not of typeE
. SeeCollections.checkedCollection
.-> in that case, you should write:
public class GenSet<E> { private E[] a; public GenSet(Class<E> c, int s) { // Use Array native method to create array // of a type only known at run time @SuppressWarnings("unchecked") final E[] a = (E[]) Array.newInstance(c, s); this.a = a; } E get(int i) { return a[i]; } }
-
Unchecked: weak typing. No type checking is actually done on any of the objects passed as argument.
-> in that case, you should write
public class GenSet<E> { private Object[] a; public GenSet(int s) { a = new Object[s]; } E get(int i) { @SuppressWarnings("unchecked") final E e = (E) a[i]; return e; } }
Note that the component type of the array should be the erasure of the type parameter:
public class GenSet<E extends Foo> { // E has an upper bound of Foo private Foo[] a; // E erases to Foo, so use Foo[] public GenSet(int s) { a = new Foo[s]; } ... }
All of this results from a known, and deliberate, weakness of generics in Java: it was implemented using erasure, so “generic” classes don’t know what type argument they were created with at run time, and therefore can not provide type-safety unless some explicit mechanism (type-checking) is implemented.