将泛型引入遗留代码并通过参数化实例进行迭代

时间:2012-04-11 12:24:53

标签: java generics

我的问题涉及将泛型引入遗留Java类。 我想要生成的下面代码中的遗留类是ClientObjectProxy和ClientObjectContainer。 ClientObject保持不变。 为简单起见,我将所有类放入一个外部类中。

现在,在遗留代码中,对未参数化的ClientObjectProxyContainer实例上的方法ClientObjectProxyContainer.getProxies()进行了多次调用。

通过引入泛型现有代码,如循环4中将不再编译,需要将调用提取到局部变量,如循环1,或者需要使用类似于循环2的带问号的声明。 新代码应该使用参数化变量,如循环3中。

我的问题是,这是我的方法,将现有代码更改为循环1或循环2,还是有一种不修改遗留代码的方法?

由于

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...
        }
    }

}

2 个答案:

答案 0 :(得分:1)

在处理泛型的代码中,尽量避免使用原始类型。当您使用这些类型时,通常会丢失比预期更多的类型信息,就像在这种情况下发生的那样。

最后一个循环中的调用proxyContainer.getProxies()实际上返回List(因为proxyContainer是原始类型,所有与其类型相关的泛型都被删除,包括方法签名中的泛型) 。如果你遍历原始的List,你只会得到Object,所以存在编译错误。您可以通过在for循环中编写(List<ClientObjectProxy>)proxyContainer.getProxies()来解决此问题(当然,您会收到警告)。

因此,使用通配符代替原始类型通常更清晰。在已经“泛化”的代码中,如果您没有具体类型,请不要使用原始类型ClientObjectProxyContainer,但始终使用ClientObjectProxyContainer<?>。此类型具有基本相同的含义,但在使用时不会导致忽略所有泛型类型。

使用通配符作为proxyContainer类型时,getProxies()的结果类型将为List<ClientProxyObject<?>>而不是List,因此您可以{{1} s out out it(但在这里,也喜欢使用ClientProxyObject!)。

答案 1 :(得分:0)

如果您介绍Generics,我更喜欢循环1方法。然后您不必担心类型检查。