2

私の質問は、Generics をレガシー Java クラスに導入することに関するものです。以下のコードから生成したい従来のクラスは、ClientObjectProxy と ClientObjectContainer です。ClientObject は変更されません。簡単にするために、すべてのクラスを 1 つの外部クラスに入れました。

現在、レガシー コードには、パラメータ化されていない ClientObjectProxyContainer インスタンスの ClientObjectProxyContainer.getProxies() メソッドの呼び出しが多数あります。

ループ 4 のような Generics の既存のコードを導入することで、これ以上コンパイルできなくなります。ループ 1 のように呼び出しをローカル変数に抽出するか、ループ 2 のように疑問符付きの宣言を使用する必要があります。新しいコードはパラメーター化されたものを使用する必要があります。ループ 3 のような変数。

私の質問は、既存のコードをループ 1 またはループ 2 に変更する方法ですか、それともレガシー コードを変更しない方法はありますか?

ありがとう

1月

import java.util.ArrayList;
import java.util.List;

public class GenericForumsExample {
    /**
     * This class is unchanged
     */
    private class ClientObject {
    }

    /**
     * @param <T> Type of the ClientObject behind this proxy
     */
    private class ClientObjectProxy<T extends ClientObject> {
    }

    /**
     * @param <T> Type of the ClientObject contained in this collection
     */
    private class ClientObjectProxyContainer<T extends ClientObject> {
        //Previous signature was:
        //  public List<ClientObjectProxy> getProxies(){
        // New signature is the following
        public List<ClientObjectProxy<T>> getProxies(){
            return new ArrayList<ClientObjectProxy<T>>();
        }
    }

    public void testScenario() {
        ClientObjectProxyContainer proxyContainer = new ClientObjectProxyContainer();
        List<ClientObjectProxy> proxies = proxyContainer.getProxies(); // Just a compiler warning

        // Loop 1
        for (ClientObjectProxy proxy : proxies) {                     // Compiler OK
            //Do something...
        }

        // Loop 2
        ClientObjectProxyContainer<?> clientObjectProxyContainer = new ClientObjectProxyContainer();
        for (ClientObjectProxy<?> proxy : clientObjectProxyContainer.getProxies()) {
            //Do something...
        }

        // Loop 3
        for (ClientObjectProxy<ClientObject> proxy : new ClientObjectProxyContainer<ClientObject>().getProxies()) {
            //Do something...
        }

        // Loop 4
        // Compiler fails on next code line
        // incompatible types
        // found   : java.lang.Object
        // required: GenericForumsExample.ClientObjectProxy
        for (ClientObjectProxy proxy : proxyContainer.getProxies()) {
            //Do something...
        }
    }

}
4

2 に答える 2

1

ジェネリックを扱うコードでは、生の型をまったく使用しないようにしてください。これらの型を使用すると、この場合のように、予想よりも多くの型情報が失われることがよくあります。

最後のループの呼び出しproxyContainer.getProxies()は、実際には a を返しますList(proxyContainerは生の型であるため、メソッド シグネチャのジェネリックを含め、その型に関連するすべてのジェネリックが削除されます)。raw を繰り返し処理すると、 sListしか得られないObjectため、コンパイル エラーが発生します。これは、for ループに記述することで解決でき(List<ClientObjectProxy>)proxyContainer.getProxies()ます (もちろん、警告が表示されます)。

したがって、生の型の代わりにワイルドカードを使用する方が通常は明確です。すでに「ジェネリック化」されているコードでは、生の型を使用しないでください。具体的な型がない場合はClientObjectProxyContainer、常にを使用してください。ClientObjectProxyContainer<?>この型は基本的に同じ意味を持ちますが、使用時にすべてのジェネリック型が無視されるわけではありません。

の型にワイルドカードを使用するとproxyContainer、 の結果の型は単なる ではなく にgetProxies()なるため、それから s を取り出すことができます(ただし、ここでも! を使用することをお勧めします)。List<ClientProxyObject<?>>ListClientProxyObjectClientProxyObject<?>

于 2012-04-11T12:51:28.680 に答える
0

Generics を導入する場合は、Loop 1 アプローチを好みます。その後、型チェックについて心配する必要はありません。

于 2012-04-11T12:53:54.783 に答える