Ответ 1
Я разберу ответ в двух частях, первый из которых касается вывода типа, а второй - по умолчанию:
Вывод типа
В Java 7 тип выражения тот же, независимо от контекста. Поэтому, когда вы делаете:
Arrays.asList(new ClassMode(), new EndMode(), ...);
Он не создает List<ISetting<?>>
. Вы можете заставить его работать, изменив тип settings
на List<? extends ISetting<?>>
. То есть список, который может содержать элементы, которые могут быть ISetting<?>
или любым подтипом:
List<? extends ISetting<?>> settings = Arrays.asList(new ClassMode(), new EndMode(), ...);
В Java 8 присвоение результирующего списка List<ISetting<?>>
работает из-за поли выражений. Это означает, что на выведенный тип некоторых выражений может влиять целевой тип. Поэтому, когда вы делаете:
private List<ISetting<?>> settings = Arrays.asList(new ClassMode(), new EndMode(), ...);
Компилятор анализирует целевой тип и неявно передает параметр типа Arrays.asList()
, что эквивалентно выполнению:
private List<ISetting<?>> settings = Arrays.<ISetting<?>>asList(new ClassMode(), new EndMode(), ...);
Что создает List<ISetting<?>>
и назначает его settings
. Вышеупомянутая форма также работает на Java 7, если вы не хотите изменять тип settings
.
Методы по умолчанию
Java 7 не имеет методов по умолчанию. Вместо этого вы можете создать абстрактную скелетную реализацию, чтобы идти вместе с вашим интерфейсом. Интерфейс определит тип, а реализация скелета предоставит функциональность по умолчанию.
Сначала поверните методы default
в свой интерфейс в регулярные объявления методов:
public interface ISetting<T> {
T getDefault();
T value();
void set(T value);
String getName();
// Former default methods:
String getValueName();
boolean isHidden();
boolean isDefault();
// etc.
}
Затем создайте абстрактный класс для хранения реализаций по умолчанию:
public abstract class AbstractSetting<T> implements ISetting<T> {
@Override
public String getValueName() {
Object obj = value();
if (obj instanceof Boolean) {
return ((Boolean) obj) ? "Yes" : "No";
}
return obj.toString();
}
@Override
public boolean isHidden() {
return false;
}
// etc.
}
Теперь сделайте, чтобы ваши конкретные классы реализовали интерфейс ISetting<T>
и расширили класс AbstractSetting<T>
. Например:
public class ConcreteSetting extends AbstractSetting<Boolean> implements ISetting<Boolean> {
// concrete implementation
}