Почему этот конвертер нуждается в кастинге?
Мне нужно реализовать преобразователь перечисления в перечисление в Java: Enum_2
> Enum_1
и я хотел бы сделать это в общем виде.
Итак, я определил интерфейс:
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
а также Enum_1
:
enum Enum_1 {
A, B;
String getValue() {
return "whatever";
}
}
а также Enum_2
который реализует LabelAware
и должен быть преобразован в Enum_1
:
enum Enum_2 implements LabelAware<Enum_1> {
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object) {
this.label = label;
this.object = object;
}
public String getLabel() {
return label;
}
public Enum_1 getObject() {
return object;
}
}
Наконец, вот общий конвертер (List.ofAll()
происходит от javaslang)
class Converter<S extends LabelAware, D extends Enum> {
private S[] values;
Converter(S[] values) {
this.values = values;
}
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
И основной метод:
public class Main {
public static void main(String[] args) {
System.out.println(new Converter<Enum_2, Enum_1>(Enum_2.values()).map("c").getValue());
}
}
Все это компилируется и работает хорошо, однако я не знаю, зачем мне нужно приводить результат Converter.map
метод для D
, так как я объявил D
расширить Enum
, Можно ли сделать это общим способом без каких-либо предупреждений?
2 ответа
Как правило, все предупреждения, связанные с универсальными шаблонами, должны обрабатываться, чтобы иметь более безопасный код и избегать цепочки предупреждений (видимое предупреждение вызвано очень далеким предупреждением цепочки зависимостей).
Но в вашем случае у вас нет проблем цепочки предупреждений, так как внешне, LabelAware
безопасно. LabelAware
имеет только внутреннее предупреждение (в своей реализации), как Enum
в extends Enum
является необработанным
Здесь, единственное отсутствующее общее объявление объясняет, почему приведение Converter.map()
метод не является безопасным: Converter
Объявление класса не определяет общий для LabelAware
,
Вы заявляете Converter
Класс как:
class Converter<S extends LabelAware, D extends Enum> {
с этими value
поле типа S
:
private S[] values;
И его map()
метод как:
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
В map()
, Вот .find(v -> v.getLabel().equals(label))
Позвони так S
экземпляр, и вы объявили, что S extends LabelAware
, Поэтому, наконец, вы получите экземпляр LabelAware
или расширяя его.
А также LabelAware
набирается с Enum
общий:
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
Итак, в map()
метод, когда .map(LabelAware::getObject)
называется, вы получаете Enum
тип.
И Enum
тип не обязательно D
типа, а обратное верно.
Поэтому, если вы хотите избежать приведения (и соответствующего предупреждения) в map()
, вы должны указать, что универсальный тип, возвращаемый getObject()
это пример D
набрав LabelAware
с D
общий:
class Converter<S extends LabelAware<D>, D extends Enum> {
Вы использовали необработанные типы в нескольких местах (не только в том, что yshavit указал в комментарии). В частности,
class Converter<S extends LabelAware, D extends Enum>
должен быть
class Converter<S extends LabelAware<D>, D extends Enum<D>>
Следующее должно компилироваться без предупреждений:
import javaslang.collection.List;
interface LabelAware<T extends Enum<?>>
{
String getLabel();
T getObject();
}
enum Enum_1
{
A, B;
String getValue()
{
return "whatever";
}
}
enum Enum_2 implements LabelAware<Enum_1>
{
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object)
{
this.label = label;
this.object = object;
}
public String getLabel()
{
return label;
}
public Enum_1 getObject()
{
return object;
}
}
class Converter<S extends LabelAware<D>, D extends Enum<D>>
{
private S[] values;
Converter(S[] values)
{
this.values = values;
}
D map(String label)
{
return List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
(РЕДАКТИРОВАТЬ: Это только говорит вам, как исправить проблему, прагматично. Смотрите ответ davidxxx для деталей о том, что пошло не так, и не забудьте оставить там +1:-))