Статический метод Java, подстановочный знак/общий тип возврата

Я создаю API, который использует абстрактные классы для вызова статических методов. Некоторый псевдокод Java:

public abstract class APIBaseClass {

    public static List<?> myMethod(Class<?> clazz, MyConverter converter, List<Object> objects) {
        return objects.stream()
                  .map(object -> converter.convertObjectToType(object, clazz))
                  .collect(Collectors.toList());
    }

}

И, где вызывается myMethod:

public abstract class MyAPIClass extends APIBaseClass {

    public static List<MyClassType> invokingMethod(MyConverter converter, List<Object> objects) {
        List<MyClassType> list = myMethod(MyClassType.class, converter, objects);
        ...
        return list;
    }
}

myMethod компилируется, как и ожидалось. И invokingMethod не компилируется, как и ожидалось, из-за несовместимых типов:

Required: List<blah.blah.blah.MyClassType>
Found:    List<capture<?>>

Он компилируется без ошибок или предупреждений, если я: (1) @SuppressWarnings("unchecked") для invokingMethod и (2) приведу результат myMethod к списку MyClassType при вызове, то есть List<MyClassType> list = (List<MyClassType>) myMethod(MyClassType.class, converter, objects);. Тем не менее, нет никакой ясности в том, что это будет необходимо любому, кто использует API, что кажется далеким от идеала.

Каковы мои варианты для myMethod, возвращающего список типа, с которым он вызывается, в invokingMethod, сохраняя при этом мои абстрактные классы и статические методы, а в идеале улучшая удобство использования в invokingMethod?

Любые предложения или альтернативные идеи приветствуются.

Заранее спасибо.


person Ryan Robison    schedule 24.10.2018    source источник
comment
myMethod(MyClassType.class, objectsList) не то же самое, что myMethod(Class<?> clazz, MyConverter converter, List<Object> objects)?   -  person tsolakp    schedule 25.10.2018
comment
Также вы имели в виду objects вместо objectsList?   -  person tsolakp    schedule 25.10.2018
comment
@tsolakp, да. Я сделал. Спасибо.   -  person Ryan Robison    schedule 25.10.2018


Ответы (1)


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

Теперь, что касается самого вопроса, вам нужно сделать метод универсальным, а метод MyConverter.convertObjectToType() тоже универсальным:

public static <T> List<T> myMethod(Class<T> clazz, MyConverter converter, List<Object> objects) {
    return objects.stream()
              .map(object -> converter.convertObjectToType(object, clazz))
              .collect(Collectors.toList());
}
person JB Nizet    schedule 24.10.2018
comment
Да, они были сделаны абстрактными, чтобы избежать конкретизации. Но я вижу вашу точку зрения в том, что он излагает антипаттерн. Спасибо, что указали на это. - person Ryan Robison; 25.10.2018
comment
Однако дженерики требуют создания экземпляра класса, верно? Это причина вашего предложения частного строителя? Или это для исправления антипаттерна? - person Ryan Robison; 25.10.2018
comment
Нет. Методы могут быть универсальными, включая статические: docs.oracle.com /javase/tutorial/extra/generics/methods.html. Кстати, Collectors.toList(), который вы используете в своем коде, является таким статическим универсальным методом. И приватный конструктор не имеет ничего общего с дженериками: он позволяет предотвратить создание экземпляра класса. - person JB Nizet; 25.10.2018
comment
Спасибо. Мне пришлось посидеть с вашим ответом несколько минут, чтобы понять его. Ты прав. Спасибо за ответ и объяснение. <T> между static и List заставило меня зациклиться на этом. - person Ryan Robison; 25.10.2018