通用:ArrayList 的?在 Java 中扩展 ISomeInterface

Generic: ArrayList of ? Extends ISomeInterface in Java

我在下面的代码中遇到了一些问题。

1
2
3
4
5
6
public ArrayList<? extends IEvent> getEventsByDateRange(DateTime minStartTime,  DateTime minEndTime)
{
    ArrayList<? extends IEvent> returnedEvents = new ArrayList<GoogleEvent>();
    returnedEvents.add(new GoogleEvent());
    return (returnedEvents);
}

这会为"returnedEvents.add(new GoogleEvent()); line of code"返回以下编译错误:

The method add(capture#1-of ? extends IEvent) in the type
ArrayList is not applicable for the
arguments (GoogleEvent)

GoogleEvent的声明如下:

1
public class GoogleEvent implements IEvent {...}

我知道在 Java 中使用泛型有一些棘手的部分,因此是通配符,但我似乎无法弄清楚这一点。

谢谢。


你为什么不写:

1
2
3
4
5
6
public List<IEvent> getEventsByDateRange(DateTime minStartTime, DateTime minEndTime)
{
    List<IEvent> returnedEvents = new ArrayList<IEvent>();
    returnedEvents.add(new GoogleEvent());
    return returnedEvents;
}


解决办法:

1
ArrayList<IEvent> returnedEvents = new ArrayList<IEvent>();

您的错误原因是因为编译器正在尝试进行捕获转换。

在您的情况下,returnedEvents 捕获了一些扩展 IEvent 的未知数(即扩展/实现 IEvent 的任何内容)并且您将其分配给参数化类型 GoogleEvent)。

编译器看到,returnedEvents.add(? extends IEvent) 没有使用 returnedEvents.add(GoogleEvent) 的签名进行验证,因为捕获占位符设置在 returnedEvents 上。


您不需要使用 ? extends IEvent,因为仅使用 IEvent,Java 将动态绑定 GoogleEvent 类。它是多态性。


这是不允许的。 returnedEvents 包含 GoogleEvent 对象的列表,不得允许接受不是 GoogleEvent 对象的对象。

虽然在您的示例中您恰好传递了一个 GoogleEvent,但您是通过调用一个接受任何实现 IEventadd 版本来实现的。根本不允许调用该 add 方法,因为它可能导致列表存储 GoogleEvent.

以外的内容

Java 通配符"编辑出"方法会以这种方式破坏规则。

如果你需要返回那个通配符列表类型,一个 ArrayList<GoogleEvent> 就可以满足它。

注意这是一个完整的源文件,编译时不会出错:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.*;

interface IEvent { }

class GoogleEvent implements IEvent { }

public class Foo {
    public ArrayList<? extends IEvent> getEventsByDateRange()  {
        ArrayList<GoogleEvent> returnedEvents = new ArrayList<GoogleEvent>();
        returnedEvents.add(new GoogleEvent());
        return (returnedEvents);
    }
}


你不能写入一个用 ? extends ... 声明的变量。仅在使用 ? super ....

时才允许写入

这可以用下面的例子来解释:

1
2
3
4
5
6
7
8
9
List<GoogleEvent> googleEvents = new ArrayList<GoogleEvent>();
ArrayList<? extends IEvent> returnedEvents = googleEvents;

// Would be OK
returnedEvents.add(new GooleEvent());

// Would be OK to the definition of returnedEvents,
// but breaks the googleEvents.
returnedEvents.add(new OtherEvent());

您的简短解决方案是将 returnedEvents 声明为 List<GoogleEvent>.


1
2
3
4
5
6
7
public ArrayList<IEvent> getEventsByDateRange(DateTime minStartTime,
        DateTime minEndTime)
{
    ArrayList<IEvent> returnedEvents = new ArrayList<IEvent>();
    returnedEvents.add(new GoogleEvent());
    return (returnedEvents);
}