3

インデックスを取得し、インデックスが有効になるまで要素をリストに追加し、そのインデックスの値を返す Java リストを使用して遅延読み込みメソッドを作成しようとしています。

たとえば、次のような List があるとし[0, 1, 2, 3]ます。それを使用してメソッドを呼び出し、インデックス 1 を渡すと、List を変更せずに 1 を返す必要があります。メソッドを呼び出してインデックス 5 を渡すと、0 (デフォルトの整数値) が返され、リストは次のようになります[0, 1, 2, 3, 0, 0]

最初は非常に簡単に実装できるように思えますが、 のようにリストを渡そうとすると問題が発生しList<List<String>>ます。リストをインスタンス化できないことはわかっているので、ArrayList を作成しようとしましたが、うまくいきません。

これが私のメソッドの現在の化身です

protected <T> T getOrCreateAt(int index, List<T> list, Class<T> elementClass) {
    while (list.size() < index + 1) {
        try {
            list.add(elementClass.newInstance());
        } catch (InstantiationException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    return list.get(index);
}

ここに私がそれを呼ぶ場所があります

List<List<String>> solutionText = new ArrayList<List<String>>();

for (Node node : solution) {
    List<String> row = getOrCreateAt(node.rowNo, solutionText, ArrayList.class);
    getOrCreateAt(node.colNo, row, String.class);
    row.set(node.colNo, String.valueOf(node.cellNo));
}

getOrCreateAt への 2 番目の呼び出しは機能しますが、最初の呼び出しはコンパイルされません。

インターフェイスと抽象クラスで遅延読み込みメソッドを機能させるにはどうすればよいですか?

4

4 に答える 4

3

この質問への答えは、これは単純な手段ではできないことを意味していると理解しています。やや不満な解決策: パラメータをパラメータ化しelementClassないようにします。

static <T> T getOrCreateAt(int index, List<T> list, Class<?> elementClass) {
    while (list.size() < index + 1) {
        try {
            list.add((T) elementClass.newInstance());
            // ...

キャストでコンパイラの警告 (チェックされていないキャスト) が表示されます。実際、残念ながら、この方法では型の安全性が失われます。

于 2012-07-22T22:11:19.873 に答える
2

私が過去にたどったパターンは、そのような工場のような振る舞いは匿名のクラスを通して達成されます。

interface Factory<T> {
    T newInstance() throws InstantiationException, IllegalAccessException;
}

次に、必要な実装

Factory<List<String>> arrayListFactory = new Factory<List<String>>() {
    @Override
    public List<String> newInstance() throws InstantiationException, IllegalAccessException {
        return new ArrayList<String>();
    }
};
Factory<String> stringFactory = new Factory<String>() {
    @Override
    public String newInstance() throws InstantiationException, IllegalAccessException {
        return String.class.newInstance();
    }
};

もちろん、クラスではなくファクトリのものを受け入れるようにメソッドを変更します。

protected static <T> T getOrCreateAt(int index, List<T> list, Factory<T> factory) {
    while (list.size() < index + 1) {
        try {
            list.add(factory.newInstance());

したがって、使用法は次のようになります

for (Node node : solution) {
    List<String> row = TestThing.getOrCreateAt(node.rowNo, solutionText, arrayListFactory);
    getOrCreateAt(node.colNo, row, stringFactory);
    row.set(node.colNo, String.valueOf(node.cellNo));
}

1つのファイルの外部でこれが必要ない場合は、おそらくそれらすべてを内部メンバーとしてそのソースファイルに貼り付けます。

于 2012-07-23T22:34:38.373 に答える
0

やってみました

protected <T> T getOrCreateAt(int index, List<T> list, Class<? extends T> elementClass) {
    // ...
}

List<String> row = getOrCreateAt(node.rowNo, solutionText, ( Class< ArrayList< String > > )solutionText.getClass());

ArrayList< String >はのサブクラスでList< String >あるため、のサブクラスも同様Class< ArrayList >ですClass< ? extends List >(ただしClass< List >)。ではないため、キャストとgetClass()呼び出しが必要です。ArrayList.classClass< ? extends List< String > >

于 2012-07-23T03:36:10.237 に答える
0

ArrayList をサブクラス化し (ジェネリックを思い出してください)、set メソッドをオーバーライドして、記述した動作を取得します。このコードは、ifnullが未割り当ての要素の値になる方法を示しています。

public T set(int index, T arg1) {
    while (index >= size()) {
        add(null);
    }
    return super.set(index, arg1);
}

newリストを割り当てるときに別の方法を使用するだけで、新しい動作で必要に応じてリストを使用できます。

これは、1 画面いっぱいのコードで実行できると思います。

于 2012-07-23T22:42:33.180 に答える