11

我正在用 Java 构建一个“联系人管理器”。

我有一个名为“ Contact的超类,它有两个基类;PersonalContactBusinessContact

我有一个名为Event的接口,它由BirthdayMeeting类实现。(Birthday 包含一个 DateTime 对象,而 Meeting 包含两个用于开始和结束时间的对象)。

PersonalContact拥有一组生日树,而BusinessContact拥有一组会议。

现在,在超类Contact中,我想创建一个名为“getEventsWithinPeriod()”的抽象方法,它将返回给定时间跨度内所有生日和/或会议的 TreeSet。

问题是,我不知道如何告诉抽象方法,然后基类方法返回什么。

例如,这是我在Contact中使用的代码;

public abstract Set<Event> getEventsWithinPeriod(DateTime start, DateTime end);

在 PersonalContact 中;

public Set<Birthday> getEventsWithinPeriod(DateTime start, DateTime end){

      Set<Birthday> birthdaysThatAreWithin = new TreeSet<Birthday>();
      //CODE
      return birthdaysThatAreWithin;

但是,在编译器中,我说错了Set<Birthday>

“返回类型与 Contact.getEventsWithinPeriod(DateTime, DateTime) 不兼容”

我应该使用什么合适的条款和回报?为什么我当前的尝试是错误的?

4

4 回答 4

10

你需要使用generic Types

public abstract class Contact<T extends Event> {
    public abstract Set<T> getEventsWithinPeriod(Date start, Date end);
}
public class BirthDay extends Contact<BirthDay> implements Event {

    @Override
    public Set<BirthDay> getEventsWithinPeriod(Date start, Date end) {
        return null;
    }
}
于 2012-11-02T16:07:39.987 回答
6

您有 3 个解决方案。

解决方案 1

首先,您可以使您的类通用,如下所示:

public abstract class Contact<E extends Event> {
    // ...

    public abstract Set<E> getEventsWithinPeriod(DateTime start, DateTime end);
}

然后在你的具体实现中:

public class PersonalContact extends Contact<Birthday> {

    public Set<Birthday> getEventsWithinPeriod(DateTime start, DateTime end) { ... }
}

这是最好的解决方案,但您有一些选择。

解决方案 2

您可以更改birthdaysThatAreWithin字段的类型:

Set<Event> birthdaysThatAreWithin = new TreeSet<Event>();

以及更改方法签名:

public Set<Event> getEventsWithinPeriod(DateTime start, DateTime end) {

并像这样返回它。这会限制您,因为您不能再将事件用作Birthday实例。

解决方案 3

您还可以将您的方法签名(在您的抽象类和具体类中)更改为:

public Set<? extends Event> getEventsWithinPeriod(DateTime start, DateTime end)

而不是改变任何其他东西。这与解决方案 2 具有相同的问题,如果不强制转换它们,您将无法将事件用作Birthday实例。

编辑: 2 和 3 的缺点是它们需要铸造。例如:

PersonalContact contact = ... ;
Set<Event> events = personalContact.getEventsWithinPeriod(start, end);
// I know all the events are birthdays, but I still have to do this:
for (Event event : events) {
    if (event instanceof Birthday) {
        Birthday birthday = (Birthday) event;
        // Do stuff with birthday
    } // else maybe log some error or something
}

使用第一个解决方案,您将拥有:

PersonalContact contact = ... ;
Set<Birthday> birthdays = personalContact.getEventsWithinPeriod(start, end);
for (Birthday birthday : birthdays) {
    // Do stuff with birthday
}

代码看起来更干净并且运行得更好,因为您不必进行instanceof检查以确保您没有获得ClassCastException. 你也可以有这样的东西:

public static void processBirthdaysFor(Contact<Birthday> birthdayContact, DateTime start, DateTime end) {
    Set<Birthday> birthdays = personalContact.getEventsWithinPeriod(start, end);
    for (Birthday birthday : birthdays) {
        // Do stuff with birthday
    }
}

而且,如果您有另一个Contact具有Birthday事件的实现,则可以将它们传递给该processBirthdaysFor方法而无需进行任何更改。

但是,如果您只需要事件而不关心调用您的代码中的类型是什么Contact.getEventsWithinPeriod,那么解决方案 2 和 3绝对是您最好的选择。如果是这种情况,我个人会使用解决方案 2。

于 2012-11-02T16:12:52.220 回答
0

覆盖任何方法时方法签名应保持不变,您的签名应保持不变并在 PersonalContact 类中返回 Set

于 2012-11-02T16:09:34.310 回答
0

使用泛型时,您不想显式指定类型。您可以绑定类型,但您不想明确。

Contact将您的方法更改为

public abstract Set<T extends Event> getEventsWithinPeriod(DateTime start, DateTime end);

并更改PersonalContact

public Set<T extends Event> getEventsWithinPeriod(DateTime start, DateTime end){

      Set<T> birthdaysThatAreWithin = new TreeSet<Birthday>();
      //CODE
      return birthdaysThatAreWithin;
}

那应该得到你想要的。

于 2012-11-02T16:10:52.670 回答