У меня есть следующий абстрактный общий держатель данных в моем проекте (упрощенный):
public abstract static class Value<E> {
E value;
public void setValue(E value) {
this.value = value;
}
public E getValue() {
return this.value;
}
public String toString() {
return "[" + value + "]";
}
}
Наряду с InputCollection
, который содержит список Objects
:
public static class InputCollection {
private ArrayList<Object> values;
public InputCollection() {
this.values = new ArrayList<>();
}
public void addValue(Value<?> value) {
System.out.println("addding " + value + " to collection");
this.values.add(value);
}
public <D> D getValue(Value<D> value, D defaultValue) {
int index = this.values.indexOf(value);
if (index == -1)
return defaultValue;
Object val = this.values.get(index);
if (val == null) {
return defaultValue;
}
return ((Value<D>)val).getValue();
}
}
Идея заключается в том, чтобы иметь возможность определять набор переменных final
, которые реализуют этот abstract
Value<E>
в так называемом "состоянии", например:
public static final class Input<E> extends Value<E> {
public static final Input<String> STRING_ONE = new Input<String>();
public static final Input<Integer> INTEGER_ONE = new Input<Integer>();
}
Затем добавление этих переменных в экземпляр InputCollection
, который, в свою очередь, разделяется многими "состояниями" или "процессами". Значение Input<E>
затем может быть изменено другим состоянием и затем извлекаться, когда это необходимо, исходным состоянием. Типичная модель общей памяти.
Эта концепция работает отлично в течение многих лет (да, это наследие), но мы недавно перешли на Java 8, и это создало ошибки компиляции, хотя реализация работала на Java 7.
Добавьте следующие теги кода main
:
public static void main (String [] args) {
InputCollection collection = new InputCollection();
//Add input to collection
collection.addValue(Input.STRING_ONE);
collection.addValue(Input.INTEGER_ONE);
//At some later stage the values are set
Input.INTEGER_ONE.setValue(1);
Input.STRING_ONE.setValue("one");
//Original values are then accessed later
long longValue = collection.getValue(Input.INTEGER_ONE, -1);
if (longValue == -1) {
System.out.println("Error: input not set");
} else {
System.out.println("Input is: " + longValue);
}
}
Если для уровня совместимости компилятора в eclipse установлено значение 1.7, проблем с компиляцией не возникает, и результат будет правильно:
addding [null] to collection
addding [null] to collection
Input is: 1
но если для строки Type mismatch: cannot convert from Integer to long
установлена ошибка компиляции 1,8 в строке
long longValue = collection.getValue(Input.INTEGER_ONE, -1);
Но если я получаю доступ к этому значению:
long longVal = Input.INTEGER_ONE.getValue();
нет проблем с компиляцией, что запутывает.
Его можно решить с помощью броска, но он используется по всему проекту и потребует довольно много обязательного тестирования для изменения каждого события.
Что изменилось в Java 8, требующем броска? Разве компиляция стала более строгой? И почему компилятор не стонет, если значение имеет доступ напрямую, а не через коллекцию?
Я читаю Как преобразовать из int в Long в Java? а также Преобразование целого в длинный, но на самом деле не получило удовлетворительных ответов на мой вопрос.