4

私は現在、受講している Java プログラミング コースの宿題に取り組んでいます。正確な答えを求めているわけではありませんが、いくつかのガイダンスを求めています。

私が取り組んでいる問題はこれです:

Filter インターフェイスを実装するフィルタ クラスがあります。このインターフェイスにはメソッドが 1 つだけあります。matches(T element)

渡された Integer の素数をチェックするようにフィルター メソッドを構成しました。

フィルターを通過したオブジェクトのみを表示するようにコレクション クラスを装飾するデコレーター クラスもあります。

contains(Object o) メソッドを正しく動作させるのに問題があります。

基本的contains(Obj o)に、クラス内のメソッドは、 FilteredCollectionまずオブジェクトがフィルターを通過するかどうかを確認し、通過する場合は、contains()そのオブジェクトの装飾されていないメソッドを呼び出す必要があります。

このクラスを多くの異なるタイプのフィルターで使用できるようにしたい場合FilteredCollection、どのタイプのオブジェクトが渡されているかを判断し、そのオブジェクトを現在実装されているフィルターに渡すことができるようにするにはどうすればよいでしょうか。

これが私のPrimeNumberFilterクラスです:

public class PrimeNumberFilter implements Filter<Integer> {

public boolean matches(Integer e) {
    int n = e.intValue();
    if (n != 2 && n % 2 == 0) {
        return false;
    }

    for (int i = 3; i * i <= n; i += 2) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

}

次に、短縮されたFilteredCollectionクラスを次に示します。

class FilteredCollection<T> implements Collection<T> {

Collection<T> fc;
Filter<T> currentFilter;

private FilteredCollection(Collection<T> coll, Filter<T> filter) {

    this.fc = coll;
    this.currentFilter = filter;

}

public static <T> FilteredCollection<T> decorate(Collection<T> coll,
    Filter<T> filter) {

    return new FilteredCollection<T>(coll, filter);
}

public boolean contains(Object o) {

    //What do I do here?
    return fc.contains(o);
}

contains メソッドに渡されるオブジェクトは、フィルター (この場合はPrimeNumberFilter.

私が得ているエラーは、オブジェクトを型 T にキャストしたいということです。消去のためにこれが機能しないことはわかっています。

私はたくさんの調査を行いましたが、リフレクションを使用する必要があるという結論に至りました。

インストラクターが教えてくれる唯一のヒントは、オブジェクトには使用できるメソッドがいくつかしかなく、そのうちの 1 つを使用する必要があるということです。

ご協力いただきありがとうございます!

編集: プロジェクトの要件の 1 つは、どのメソッドでもオブジェクトを T にキャストしないことです。したがって、これらの回答は素晴らしいものですが、私はそれらのいずれも使用できません。

4

4 に答える 4

4

コードに問題はありません。

この問題は、java.util.Collection.contains(Object o)インターフェイス メソッドが一般的に型指定されていないことが原因です。これはあなたの管理外です。

オプション 1: シンプルなアプローチ

そのメソッドの実装では、次をキャストできます。

public boolean contains(Object o) {
    return o != null && currentFilter.matches((T)o) && fc.contains(o);
}

オプション 2: getParameterType() メソッドを Filter インターフェースに追加する

このメソッドは、さまざまなサブクラスで実装されているフィルターのジェネリック型を返します。

interface Filter<T> {
    boolean matches(T parameter);
    Class<T> getParameterType();
}

それで...

public boolean contains(Object o) {
    return o != null && currentFilter.getParameterType().isAssignableFrom(o.getClass()) && currentFilter.matches((T)o) && fc.contains(o);
}

オプション 3: リフレクションを介してジェネリック型を決定する

技術的には、フィルターのジェネリック型は実行時に実際には消去されません。PrimeNumberFilter は、ジェネリックに型指定されたインターフェイスを実装する実際のクラスであるため、ここでは型消去は適用されません。

@SuppressWarnings("unchecked")
public boolean contains(Object o) {
    Class<?> genericTypeOfFilter = getGenericTypeOfFilter(currentFilter);
    return o != null && genericTypeOfFilter.isAssignableFrom(o.getClass()) && currentFilter.matches((T)o) && fc.contains(o);
}

static <T> Class<T> getGenericTypeOfFilter(Filter<T> filter) {
    try {
        @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
        Class<T> type = (Class<T>) ((ParameterizedType)filter.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
        return type;
    }
   catch (Exception e) {
        throw new IllegalStateException("Unexpectedly failed to read generic type of filter: " + filter, e);
    }
}

この場合、オプション 2 を使用するのが私のコードであれば、リフレクションに依存するよりも堅牢です。

于 2013-05-15T17:38:08.533 に答える
4

使用方法はObject.equals(Object). コレクションfcを反復して、要素が含まれているかどうかを確認できますequals(o)。その場合は、その要素 (タイプはT) を続行します。

for(T e : fc) {
    if(o.equals(e)) {
        // carry on with e
    }
}

をカバーすることもできますo == null

于 2013-05-15T18:53:45.243 に答える
0

への型キャストは機能します。消去のためにキャストの前に型を確認できないため、 sTをキャッチするように注意する必要があります。ClassCastException

これにより、次のようなものが残ります。

public boolean contains(Object other) 
{
  try
  {   
    return currentFilter.matches((T)other) && fc.contains(other);
  }
  catch (ClassCastException e)
  {
    //Add some logging.
    return false;
  }
}

このように例外を使用することは一般的に嫌われますが、この場合はあまり選択肢がありません。

于 2013-05-15T17:42:30.767 に答える