I am having a specific problem implementing a parametrised class Parameter, but this is something I have come across before with generics, so a general solution would be good..
The class Parameter stores a value of one of a strict number of classes:
public class Parameter<T> {
/*
* Specify what types of parameter are valid
*/
private static final Set<Class<?>> VALID_TYPES;
static {
Set<Class<?>> set = new HashSet<Class<?>>();
set.add( Integer.class );
set.add( Float.class );
set.add( Boolean.class );
set.add( String.class );
VALID_TYPES = Collections.unmodifiableSet(set);
}
private T value;
public Parameter(T initialValue) throws IllegalArgumentException {
// Parameter validity check
if (!VALID_TYPES.contains(initialValue.getClass())) {
throw new IllegalArgumentException(
initialValue.getClass() + " is not a valid parameter type");
}
value = initialValue;
}
public T get() { return value; }
public void set(T value) {
this.value = value;
}
}
This is all fine, until I try and store instances of Parameter in a collection. For example:
Parameter<Integer> p = new Parameter<Integer>(3);
int value = (Integer)p.get();
p.set(2); // Fine
ArrayList<Parameter<?>> ps = new ArrayList<Parameter<?>>();
ps.add(p);
value = (Integer)(ps.get(0).get());
ps.get(0).set(4); // Does not compile due to type erasure
What would others do in this situation to get round this?
Thanks
Well, you can't directly work around this.. But perhaps you could remember the class of the initial value?
class Parameter<T> {
// ...
private T value;
private final Class<?> klass;
public Parameter(T initialValue) throws IllegalArgumentException {
if (!VALID_TYPES.contains(initialValue.getClass()))
throw new IllegalArgumentException(...);
value = initialValue;
klass = initialValue.getClass();
}
@SuppressWarnings("unchecked")
public void set(Object value) {
if (value != null && value.getClass() != klass)
throw new IllegalArgumentException(...);
this.value = (T)value;
}
However, you will lose compile-time type checks on set()..