我正在用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)不兼容”
我应该使用的正确条款和回报是什么?为什么我目前的尝试错了?
答案 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;
}
那应该得到你想要的东西。