我目前正在重构一些旧代码,并且发现了一个片段,在该片段中我不理解如何为Swing应用程序框架类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. failedorg.jdesktop.application.TaskListener.Adapter方法的声明为public void failed(TaskEvent<Throwable> event),但是如果我尝试将代码更改为此:

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


我得到“方法不会覆盖父类型的方法”。同样,我必须使用原始的TaskEvent。这是为什么?

谢谢您的帮助。

编辑:Jarvana上TaskListener的Javadoc。

最佳答案

您不能将通用化为<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);
}


至于第二部分,我不知道-对我来说也很好。也许这是来自原始类型的一些误导性错误,尽管由于根本没有任何通用参数涉及到声明,所以这似乎不太可能。如果在完成上述更改后编译器仍然不喜欢覆盖,则问题可能出在其他地方(例如您不小心将方法放置在错误的类的范围内,等等)。

09-13 13:52