Как исправить "непроверенный актерский состав" из Generics для другого интерфейса - PullRequest
0 голосов
/ 16 января 2019

Не проверено приведение: от 'zzz.szi.m.Something1' до 'T'

Я получаю предупреждения при запуске «mvn package»

private <T> T get() throws Exception {
    T m;

    if (/*some condition*/) {
        m = (T)new Something1()
    }
    elseif (/*some condition*/) {
        m = (T)new Something2()
    }
    else {
        m = (T)new Something3()
    }
    return m;
}

мой класс:

public class Something1 implements Something {
    // ...
}
public class Something2 implements SomethingElse {
    // ...
}
public class Something3 implements Something, SomethingElse, SomethingMore {
    // ...
}

// добавлено приведение к (T), но результат тот же

Я не хочу предупреждений

Ответы [ 2 ]

0 голосов
/ 17 января 2019

T определяется компилятором, смотрящим на контекст вызова этого метода. Если результат вызова должен быть назначен переменной, набранной XXX, тогда T будет заменено на XXX во время компиляции, чтобы проверить логику остальной части кода.

Код вопроса нарушает этот контракт, так как кажется, что код метода контролирует возвращаемый тип, и поэтому он, как правило, не может сделать правильный выбор с точки зрения класса для создания экземпляра. Вот почему этот состав небезопасен.

Способ исправить это - вернуть элемент управления к вызывающему коду. Например, метод get() может принять объект класса, который указывает возвращаемый тип, и использовать Class.newInstance для создания объекта с неудобством необходимости обработки соответствующего проверенного исключения и вероятностью того, что запрошенный класс не имеет Конструктор без параметров:

private <T> T get(Class<? extends T> class) {
    try {
      return class.newInstance();
    } catch (Exception ex) {
      // handle the exception apropiately
    }
}

Телефонный код:

Something some;
if (/* condition 1 */) {
   some = get(Something1.class);
} else if (/* condition 2 */) {
   some = get(Something2.class);
}  ...

Остается вопрос, есть ли у вас общий код, не зависящий от подкласса, для добавления в тело get до или после создания экземпляра объекта, чтобы сделать этот метод стоящим, в противном случае было бы лучше просто вызвать соответствующий конструктор подкласса в каждом if-else (т.е. new Something1(), new Something2() и т. д.).

0 голосов
/ 16 января 2019

Когда вы делаете свой метод универсальным, это означает, что вызывающая сторона имеет контроль над параметром типа.Абонент всегда может предоставить все, что встречает любые границы, и у вас нет границ.Вызывающий может предоставить Integer, Object или Foo, и этот метод должен возвращать экземпляр этого типа.

Однако это не имеет ничего общего с условиями в логике вашегометод, по словам компилятора.Он не может гарантировать, что то, что вы возвращаете, совпадает с параметром типа, что и пытается сказать компилятор.

Ваш метод не может быть здесь универсальным.Если все ваши SomethingX классы наследуются от базового класса или интерфейса, то ваш метод должен вернуть этот тип, иначе он должен быть Object.Если вам нужно вызвать один конкретный метод, который есть у всех ваших SomethingX классов, извлеките новый интерфейс и попросите ваш метод вернуть этот тип.

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

private Object get() throws Exception {
    Object m;

    if (/*some condition*/) {
        Something1 s1 = new Something1();
        s1.s1Method();
        m = s1;
    }
    else if (/*some condition*/) {
        Something2 s2 = new Something2();
        s2.s2Method();
        m = s2;
    }
    else {
        Something3 s3 = new Something3();
        s3.s3Method();
        m = s3;
    }
    return m;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...