2016-11-05 4 views
9

Мне нужно реализовать enum для преобразования enum в 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. Можно ли это сделать общим способом без каких-либо предупреждений?

+0

Разве не 'List.of (values)' типа 'S'? –

+2

Я нахожусь на своем телефоне, так что его трудно прочитать, но обратите внимание, что Enum - это общий класс, поэтому ваши дженерики включают в себя необработанный тип, как написано. Обычно вам нужно '>'. Не уверен, что это ваша проблема. – yshavit

+0

@yshavit, ничего не меняет - все еще присутствует предупреждение. – Opal

ответ

5

Как правило, все предупреждения, связанные с дженериками, должны быть обработаны, чтобы иметь более безопасный код и избегать цепи предупреждения (видимое предупреждение вызвано очень далеким предупреждением о цепочке зависимостей).

Но в вашем случае у вас нет проблемы с цепью предупреждения, так как извне, 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> { 
4

Вы использовали необработанные типы в нескольких местах (не только тот, который указал 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("")); 
    } 
} 

(EDIT:. Это говорит лишь о том, как решить эту проблему, прагматично см answer by davidxxx для получения информации о том, что пошло не так, и не забудьте оставить +1 там :-))

Смежные вопросы