2014-09-03 2 views
9

Предположим, у меня есть универсальный класс, который я использую, который объявлен как это:Java общий объект с несколькими интерфейсами литья

public class ConfigurableRuleKey<R extends Configurable & Rule> extends Key<R> { 

    private final R rule 

    public ConfigurableRuleKey(R rule) { 
     this.rule = rule; 
    } 

    /* Additional methods are declared here */ 

} 

И я хочу, чтобы реализовать фабричный метод, который проверяет, если он принят правило реализует интерфейс Configurable при создании конфигурируемый правило или просто создать основной ключ:

public static <R extends Rule> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return new ConfigurableRuleKey<>(rule); //This will not compile 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 

проблема заключается в том, что в моем методе фабрики я не могу передать правило конструктор ConfigurableRuleKey, поскольку он не соответствует заявленным общие ограничения (событие, если бы я ехр законно проверил, что он реализует Configurable). Вопрос в том, как я могу нарисовать свой экземпляр правила, чтобы он соответствовал ограничениям конструктора в ConfigurableRuleKey?

ответ

3

Я нашел способ сделать то, что вы спрашиваете без использования сырья типов, но она по-прежнему включает в себя пару непроверенных слепков:

@SuppressWarnings("unchecked") 
public static <R extends Rule, T extends Rule & Configurable> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return (Key<R>)new ConfigurableRuleKey<>((T)rule); 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 

я не уверен, если это лучше, чем ответ sp00m, но это по-другому. :)

Исключительная причина, по которой это невозможно правильно построить в генераторах Java, похоже, состоит в том, что типы пересечений должны быть построены из конкретных интерфейсов и не могут быть построены из других переменных типа. Следовательно, нет способа построить T в этом примере таким образом, чтобы он ограничивался R. Без этой возможности нет даже способа иметь волшебный метод, родственный Class.asSubclass, чтобы отвлечь это поведение.

EDIT: В связи с этим, похоже, что Java 8 представила анонимные типы пересечений, где вы можете использовать несколько интерфейсов - например. (Configurable & Rule)rule - но даже это не поможет здесь, поскольку по той же причине, что и выше, вы не можете наложить на (Configurable & R). Это поможет избавиться от типа переменной T, однако:

@SuppressWarnings("unchecked") 
public static <R extends Rule> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return (Key<R>)new ConfigurableRuleKey<>((Configurable & Rule)rule); 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 
+0

Моя IDE говорит мне, что этот код даже не компилируется, но на самом деле кажется, что он это делает. :) Благодаря. Я думаю, что я расскажу об этой проблеме для поддержки моей IDE. – SimY4

+0

@ SimY4: Просто из любопытства, о чем жалуется IDE? – Dolda2000

+0

Я использую IntelliJ Idea 14 Early Access Preview – SimY4

2

Это должно удовлетворить ваши потребности:

@SuppressWarnings({ "rawtypes", "unchecked" }) 
public static <R extends Rule> Key<R> create(R rule) { 
    if (rule instanceof Configurable) { 
     return new ConfigurableRuleKey((Configurable) rule); 
    } else { 
     return new RuleKey<>(rule); 
    } 
} 

Вы вручную проверить, что rule является Configurable, поэтому приведение в безопасности.

+0

Вы используете сырые типы и подавить все предупреждения, я думаю, что это не то, что ОП хочет. – WilQu

+0

@WilQu: Я сомневаюсь, что возможно сделать то, что хочет OP, не нарушая при этом дженериков, потому что для того, чтобы фактически создать экземпляр 'ConfigurableRuleKey' напрямую, нужен конкретный тип, который является как' Configurable', так и 'Rule', и Функция 'create' не имеет доступа к такому конкретному типу. – Dolda2000

+0

@WilQu Я не подавляю все предупреждения, только «rawtypes», так что компилятор не проверяет генераторы (я не уверен, что это можно сделать иначе), а «unchecked», поскольку компилятор не может узнайте, безопасен ли бросок (в то время как он точно проверен вручную с помощью 'instanceof'). – sp00m

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