11

Javaで「ContactManager」を構築しています。

「 Contact」というスーパークラスがあり、 PersonalContactBusinessContactの2つの基本クラスがあります。

私はEventと呼ばれるインターフェースを持っています。これは、 BirthdayクラスとMeetingクラスによって実装されます。(誕生日には1つのDateTimeオブジェクトが含まれ、会議には開始時刻と終了時刻に2つのオブジェクトが含まれます)。

PersonalContactは誕生日のTreeSetを保持し、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)

他には何も変更しません。Birthdayこれにはソリューション2と同じ問題があり、イベントをキャストせずにインスタンスとして使用することはできません。

編集: 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 に答える