#java #generics
#java #дженерики
Вопрос:
У меня есть класс
public abstract class AbstractE<T, E extends Enum<E> amp; Flags>
{
public interface Flags{} /*marker interface*/
//...
//other code
}
и интерфейс
public interface IXYZAdapter
{
public <E extends Enum<E> amp; Flags> Set<E> getFlags();
}
Где Flags — это интерфейс, определенный в самом AbstractE.
M расширяет абстракцию таким образом:
public class M extends AbstractE<Long, M.EF> implements IXYZAdapter
{
public enum EF implements AbstractE.Flags{flag1, flag2}
@Override /*from IXYZAdapter*/
public Set<M.EF> getFlags()
{return EnumSet.allOf(EF.class);}
}
Теперь из основного кода я пытаюсь получить дескриптор интерфейса IXYZAdapter и вызвать метод getFlags
IXYZAdapter adapter = (IXYZAdapter)m; //where m is an instance of AbstractE
Set s = adapter.getFlags();
Я получаю следующую ошибку во время компиляции в последней строке основной программы (Set s = adapter.getFlags();)
недопустимые выведенные типы для E; выведенный тип не соответствует объявленным границам
inferred: AbstractE.Flags bound(s): java.lang.Enum<AbstractE.Flags>,AbstractE.Flags
Что я делаю не так?
Я использую Java 6
Отредактировано, чтобы указать местоположение ошибки
Комментарии:
1. какая строка вызывает ошибку компилятора?
2. Когда я пытаюсь скомпилировать, строка Set s = adapter.getFlags() — выдает ошибку
3. что
return new EnumSet.allOf(EF.class);
предполагается означать / делать?4. Я удалил ключевое слово «new» перед EnumSet.Все, что было введено там по ошибке
5. также ваша первая строка
public abstract class AbstractE<T, E extends Enum<E> amp; Flags>
выдает мне ошибку компилятора, это должно бытьpublic abstract class AbstractE<T, E extends Enum<E> amp; AbstractE.Flags>
. пожалуйста, используйте copy / paste при задании такого рода сложных вопросов 🙂
Ответ №1:
Попробуйте это:
public interface IXYZAdapter <E extends Enum<E> amp; AbstractE.Flags>
{
public Set<E> getFlags();
}
И
public class M extends AbstractE<Long, M.EF> implements IXYZAdapter<M.EF>
{
}
Или
Set<M.EF> s = adapter.getFlags();
Проблема в том, что с Set s = adapter.getFlags();
система не знает, какой тип выводить для E в IXYZAdapter, и, следовательно, E в AbstractE не совпадает.
Редактировать:
Другим вариантом может быть:
interface IXYZAdapter <E extends Enum<E> amp; AbstractE.Flags>
{
public Set<? extends E> getFlags();
}
class M extends AbstractE<Long, M.EF> implements IXYZAdapter<M.EF>
{
public enum EF implements AbstractE.Flags{flag1, flag2}
public Set<? extends M.EF> getFlags()
{return EnumSet.allOf(EF.class);}
}
И вызов: Set<? extends AbstractE.Flags> s = adapter.getFlags();
Это позволило бы вам получить набор флагов без приведения и принудительно объявить флаги как enum.
Комментарии:
1. оба этих решения требуют, чтобы программист знал тип enum при вызове getFlags, иначе будут хотя бы предупреждения.
2. ну, на самом деле это не совсем так. зависит от того, как вы пишете основной метод 🙂 я приведу пример!
Ответ №2:
используя первое решение, предоставленное Томасом, метод main может быть написан следующим образом, чтобы стать свободным от предупреждений, фактически не имея необходимости знать о типе enum:
public static void main(String[] args) {
M m = new M();
IXYZAdapter<?> adapter = (IXYZAdapter<?>)m;
Set<?> flags = adapter.getFlags();
Iterator<?> it = flags.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
Комментарии:
1. Вы не получаете предупреждений, но вам все равно придется приводить элементы набора к
AbstractE.Flags
. В этом случае я бы изменил подпись наSet<? extends AbstractE.Flags> getFlags();
, а затем вызвалSet<? extends AbstractE.Flags> s = adapter.getFlags();
.2. не могли бы вы уточнить? этот код работал нормально, и я получил имена перечислений для печати таким образом. звучит так, как будто вы подразумеваете, что приведенный выше код не должен работать. я что-то упускаю?
3. Нет, приведенный выше код работает. Но попробуйте это:
AbstractE.Flags f = it.next();
. Вам пришлось бы сделать это в вашем случае:AbstractE.Flags f = (AbstractE.Flags)it.next();