2

オブジェクトを文字列に変換するためのインターフェイスがあります。

public interface Converter<T> {
    String asString(T object);
}

そして、利用可能なすべてのコンバーターを格納するためのマップ:

Map<Class<?>, Converter<?>> converterMap;

これで、次のように変換する異種データのリストができました。

List<?> data = fetchData();
List<String> stringData = new ArrayList<>(data.size());
for (Object datum : data) {
    stringData.add(convertrMap.get(datum.getClass()).asString(datum));
}

しかし、このコードはコンパイルされません:

error: method asString in interface Converter<T> cannot be applied to given types;
            stringData.add(converterMap.get(datum.getClass()).asString(datum));
  required: CAP#1
  found: Object
  reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
  where T is a type-variable:
    T extends Object declared in interface Converter
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?

コードをどのように変更すればよいですか?

4

3 に答える 3

4

ワイルドカードキャプチャと呼ばれる問題に直面しています。List<?>Javaは、データから受信するタイプを識別できません。2つの方法のいずれかでコードをリファクタリングしてみてください

方法1:インターフェースを以下のように変更します

interface Converter {
    String asString(Object object);
}

方法2:型推論によってワイルドカードをキャプチャするヘルパーメソッド

以下のようにヘルパーメソッドを作成します。

// Helper method created so that the wildcard can be captured
// through type inference.
private <T> void helper(List<T> data) {
    Map<Class<?>, Converter<T>> converterMap = null;
    List<String> stringData = null;

    for (T datum : data) {
        stringData.add(converterMap.get(datum.getClass()).asString(datum));
    }
}

このヘルパーメソッドを以下のように呼び出します

List<?> data = fetchData();
helper(data);
于 2012-12-25T03:02:04.947 に答える
1

まず、マップを次のようなヘルパークラス内にカプセル化する必要があります。このクラスの操作では、不変条件(にClass<T>マップされるConverter<T>)が保持されます。

public class ConverterMap {
    Map<Class<?>, Converter<?>> converterMap = new HashMap<Class<?>, Converter<?>>();
    public <T> void addConverter(Class<T> clazz, Converter<T> converter) {
        converterMap.put(clazz, converter);
    }
    @SuppressWarnings("unchecked")
    public <T> Converter<T> getConverter(Class<T> clazz) {
        return (Converter<T>)converterMap.get(clazz);
    }
}

ここで、タスクを分解するために、任意のオブジェクトを取得し、コンバーターマップに基づいて変換する関数を作成する小さなステップを実行しましょう(オブジェクトのクラスがコンバーターマップにあると仮定します)。

ConverterMap cm = new ConverterMap;
private static String convert(Object x);

これは単純に見えますが、Java型システムの特殊なケースに遭遇するため、見た目よりも難しくなります.getClass()xのパラメータのインスタンスであるコンパイラを説得するという問題が発生しますx.getClass()。これを解決する最良の方法は次のとおりです。

@SuppressWarnings("unchecked")
private static <T> String convert2(Class<T> clazz, Object x) {
    return cm.getConverter(clazz).asString((T)x);
    // you can alternately do clazz.cast(x) instead of the unchecked cast (T)x
}
private static String convert(Object x) {
    return convert2(x.getClass(), x);
}

そして、残りの問題を解決できます。

for (Object datum : data) {
    stringData.add(convert(datum));
}
于 2012-12-25T09:28:14.763 に答える
0

次のようにコードを変更する必要があります。

public interface Converter {
    String asString(Object object);
}

私はそれがうまくいくと思います。

于 2012-12-25T03:03:11.113 に答える