为实现相同接口的两个子类定义泛型方法

时间:2012-11-02 16:02:06

标签: java generics set

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

我有一个名为“联系人的超类,它有两个基类; PersonalContact BusinessContact

我有一个名为事件的界面,该界面由生日会议类实施。 (生日包含一个DateTime对象,而会议有两个开始和结束时间)。

PersonalContact 包含生日的TreeSet, BusinessContact 包含一组会议。

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

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

例如,这是我在联系;

中使用的代码

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 个答案:

答案 0 :(得分: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;
    }
}

答案 1 :(得分: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 肯定< / em>你最好的赌注。如果出现这种情况,我个人只会使用解决方案2.

答案 2 :(得分:0)

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

答案 3 :(得分: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;
}

那应该得到你想要的东西。