10

リストで特定のテストを実行したい。リストには、まったく異なるクラスを含めることができます。

リストの一貫性をチェックする方法が 1 つあります。null ではなく、空ではなく、x 要素以下です。これはすべてのリストに共通です。次に、オーバーロードを使用して、各オブジェクトをテストします。

アイデアは次のようになります。

public static <T> void check(List<T> list) {

    //do general checks

    for (T element : list) {
        check(element);
    }
}

その後

public static void check(SomeType element) {...}

public static void check(SomeOtherType element) {...}

しかし、次のようなメソッドも追加する必要がありました。

public static void check(T element) {...}

そして、これは実行時に呼び出されました-特定のクラスを持つ他のメソッドではありません。クラスはまったく同じでしたが。私は明らかにいくつかのジェネリックの理解を欠いています。

ここで、一般的な方法をまったく使用せず、次の方法で解決しようとすると:

    public static void check(List<SomeType> list) {...}

    public static void check(List<SomeOtherType> list) {...}

コンパイラ エラー - 「メソッド check(List) には、別のメソッドと同じ消去 check(List) があります...」

それで、これに対するエレガントな解決策はありますか?別のメソッド名を使用することもできますが、それなしでどのように可能か知りたいです。

ありがとう!

4

5 に答える 5

10

これは、あなたが見逃しているジェネリックに関するものではありません。Java には二重ディスパッチがありません。への呼び出しcheckはコンパイル時に解決する必要があり、コンパイラは指定されたシナリオであるかどうcheck(T)かを判断できないため、一致するのはこれだけです。可能なすべての s に対して機能する、呼び出すメソッドを 1 つ選択する必要があります。TSomeTypeSomeOtherTypeT

これは、訪問者パターンを使用して解決されることがあります。

于 2013-01-30T16:00:05.747 に答える
4

instanceofディスパッチに使用できます:

public static <T> void check(List<T> list) {
  for (T element : list) {
    check(element);
  }
}

public static void check(T t) {
  if (t instanceof SomeType) {
    SomeType someType = (SomeType) t;
    // code for SomeType ...
  } else if (t instanceof OtherType) {
    OtherType otherType = (OtherType) t;
    // code for OtherType ...
  } else {
    // we got a type that we don't have a method for
  }
} 
于 2013-01-30T16:00:59.640 に答える
4

問題は発信者が解決する必要があります。クラスを T の具象型でインスタンス化する場合Checker<T>、同じ具象型ののインスタンスも渡す必要があります。

public class SomeClass<T> {
    private List<T> list;
    private Checker<T> checker;

    public SomeClass(Checker<T> checker) {
        this.checker = checker;
    }

    public void check() {
        checker.check(list);
    }
}

public interface Checker<T> {
    public void check(List<T> list);
}

...

SomeClass<Foo> someClass = new SomeClass<Foo>(new Checker<Foo>() {
    @Override 
    public void check(List<Foo> list) {
        // do whatever you want here
    }
});
于 2013-01-30T16:02:46.540 に答える
2

ジェネリックスでは、型パラメーターはコンパイル中に実際に消去され、リストオブジェクトはそれに含まれるオブジェクトの静的型について何も知りません。Javaは複数のディスパッチをサポートしていないため、それを認識していないため、オーバーロードを使用して異なるパラメーターを持つメソッドを呼び出すことはできません。

次に、3つの選択肢があります。

  • オブジェクトCheckedに、チェックロジックを実行するチェックメソッドを使用したインターフェイスを実装させます。欠点は、チェックロジックがいくつかの場所に分散されていることであり、制御できないクラスのオブジェクトがある場合は実用的ではありません。
  • オブジェクトの動的タイプに従ってメソッドinstanceofを明示的に呼び出すために使用します。check欠点は、大きなif/elseブロックを維持するのが少し難しくなる可能性があることです。
  • ビジターパターンを実装します。欠点は、オブジェクトクラスも変更する必要があることですが、checkロジックは1か所にとどまります。
于 2013-01-30T16:01:12.847 に答える
1

変数の型が失われるため、次のcheck(List<T> list)2 つのオプションがあります。

1. ランタイム タイプをチェックしてさまざまなことを行う

check(T element) {
  if (element.getClass().equals(SomeType.class)) {
    check((SomeType) element);
  } elseif (element.getClass().equals(SomeOtherType.class)) {
    check((SomeOtherType) element);
  }

これはもう少し洗練されたものにすることができます。たとえば、各チェックを でラップCallableし、Map<Class, Callable>

これは、訪問者のパターンに似ています。

2.チェックする要素自体で仮想メソッドを呼び出す

チェック ロジックをチェック対象のオブジェクト自体にプッシュできる場合 (これは必ずしも悪いことではありません)、型をチェックする必要はありません。

interface Checkable { void check(); }
class SomeType implements Checkable { .... }
class SomeOtherType implements Checkable { .... }

それで:

public static <T extends Checkable> void check(List<T> list) {
    for (T element : list) {
        element.check();
    }
}

これらは2 つのオプションのみです。どの実装も、これらのいずれかのバリエーションでなければなりません。

于 2013-01-30T18:27:06.993 に答える