До того, как я упрекнул меня за то, что я не выполнил свою домашнюю работу, я не смог найти никаких подсказок по множеству вопросов о дженериках Java и динамическом приведении.
Тип Скаляр определяется следующим образом:
public class Scalar <T extends Number> {
public final String name;
T value;
...
public T getValue() {
return value;
}
public void setValue(T val) {
this.value = val;
}
}
Я хотел бы иметь метод, который выглядит следующим образом:
public void evilSetter(V val) {
this.value = (T) val;
}
Конечно, это обычно не рекомендуется. Причина, по которой я хочу такой метод, заключается в том, что у меня есть коллекция скаляров, значения которых я бы хотел изменить позже. Однако, как только они попадают в коллекцию, их параметры общего типа больше не доступны. Поэтому, даже если я хочу сделать назначение, которое будет полностью допустимым во время выполнения, нет никакого способа узнать, что оно будет действительным во время компиляции, с генериками или без них.
Map<String, Scalar<? extends Number>> scalars = ...;
Scalar<? extends Number> scalar = scalars.get("someId");
// None of this can work
scalar.value = ...
scalar.setValue(...)
Так как мне реализовать проверенный метод приведения и установки?
public <V extends Number> void castAndSet(V val) {
// One possibility
if (this.value.getClass().isAssignableFrom(val.getClass()) {
// Some cast code here
}
// Another
if (this.value.getClass().isInstanceOf(val) {
// Some cast code here
}
// What should the cast line be?
// It can't be:
this.value = this.value.getClass().cast(val);
// Because this.value.getClass() is of type Class<?>, not Class<T>
}
Так что мне осталось использовать
this.value = (T) val;
и перехват исключения ClassCastException?