Понимание общих параметров типа TaskListener - PullRequest
2 голосов
/ 11 августа 2011

В настоящее время я работаю над рефакторингом старого кода и нашел фрагмент, в котором я не понимаю, как правильно использовать Generics для класса Swing Application Framework TaskListener.Adapter.

Это соответствующий кодфрагмент:

public void executeTask(Task<?, ?> task, boolean handleException) {
    task.addTaskListener(new TaskListener.Adapter() { /* <-- Two warnings here */
        @Override
        public void failed(TaskEvent event) { /* ... */ }
    });
    getContext().getTaskService().execute(task);
}

1.Сначала я хочу избавиться от предупреждений. "непроверенное преобразование" и "найденный необработанный тип" .Я попытался изменить код на new TaskListener.Adapter<Object, Object>, но затем я получаю сообщение об ошибке "невозможно применить к данным типам" .Является ли необработанный тип единственным, что я могу использовать здесь из-за объявления (Task<?, ?>?

2.Объявление метода failed в org.jdesktop.application.TaskListener.Adapter - public void failed(TaskEvent<Throwable> event), но если я попытаюсь изменить свой код следующим образом:

@Override
public void failed(TaskEvent<Throwable> event) { /* ... */ }

I get "метод не переопределяет метод изсупертип ".Я снова должен идти с сырым TaskEvent.Почему это так?

Спасибо за вашу помощь.

РЕДАКТИРОВАТЬ: Javadoc для TaskListener на Jarvana .

Ответы [ 3 ]

2 голосов
/ 11 августа 2011

Нельзя применить адаптер, обобщенный как <Object, Object> к Task<?, ?>, потому что, кто знает, что такое подстановочные знаки? Это может быть Task<String, Integer>, в этом случае границы адаптера не будут совпадать, и поэтому он не будет применим.

(Ну, может быть, в этом случае они в порядке, потому что они потребители, но компилятор не может сделать это самостоятельно. Если это , то Task.addTaskListener нужно быть объявленным для получения TaskListener<? super T, ? super V> для удовлетворения компилятора.)

Из-за способа объявления addTaskListener вам необходимо передать слушателю с точно такими же общими границами. И это невозможно, когда вы объявляете их подстановочными знаками, поскольку у вас нет возможности вернуться к ним позже. Вместо этого вам нужно сделать метод родовым, что аналогично использованию подстановочных знаков ?, за исключением того, что вы присваиваете им имена, чтобы вы могли ссылаться на них позже в методе:

public <T, V> void executeTask(Task<T, V> task, boolean handleException) {
    task.addTaskListener(new TaskListener.Adapter<T, V>() {
        @Override
        public void failed(TaskEvent event) { /* ... */ }
    });
    getContext().getTaskService().execute(task);
}

Что касается второй части, я понятия не имею, мне она тоже выглядит хорошо. Возможно, это какая-то вводящая в заблуждение ошибка, исходящая от необработанных типов, хотя это кажется маловероятным, поскольку ни один универсальный параметр вообще не участвует в объявлении. Если компилятору по-прежнему не нравится переопределение после вышеуказанных изменений, возможно, проблема в другом месте (например, вы случайно поместили метод в область неправильного класса и т. Д.)

1 голос
/ 11 августа 2011

Не зная библиотеку и исходный код, вот мое предположение:

public <K, V> void executeTask(final Task<K, V> task, boolean handleException) {
    task.addTaskListener(new TaskListener.Adapter<K, V>() {
        @Override
        public void failed(final TaskEvent<Throwable> event) {
            super.failed(event);
        }
    });
    getContext().getTaskService().execute(task);
}

(Правка: я скачал lib и приведенный выше код компилируется без предупреждения)

1 голос
/ 11 августа 2011
  1. Вы пробовали new TaskListener.Adapter<?, ?>?

  2. Когда вы пытались добавить параметр типа <Throwable>, ваш new TaskListener.Adapter был создан как необработанный тип или у него были параметры общего типа?

    В первом случае происходит то, что компилятор обрабатывает класс целом (и его суперкласс) как необработанный тип (для обратной совместимости). То есть все параметры общего типа внутри класса, независимо от того, являются ли они специфичными для класса или метода , опущены. Поэтому, когда он находит объявление вашего метода с универсальным параметром, он сравнивается с методом суперкласса с параметром raw . Следовательно, нет совпадений.

...