让我们拥有超类ProxyHost和扩展类HttpProxyHostHttpsProxyHostsSocks4ProxyHostSocks5ProxyHost

让我们在这些秘诀类上有几个集合:

private ArrayList<HttpsProxyHost> httpsProxies = new ArrayList<>();
private ArrayList<Socks5ProxyHost> socks5Proxies = new ArrayList<>();
private ArrayList<HttpProxyHost> httpProxies = new ArrayList<>();
private ArrayList<Socks4ProxyHost> socks4Proxies = new ArrayList<>();


现在我要做的是做类似的事情(下面的两个变体都失败了):

    private <T extends ProxyHost> void processRow(Element row, T h, ArrayList<T> httpProxies) {
        h.setIp("someIp");
        h.setOrigin("Some origin");
        h.setPort(1234);
        httpProxies.add(h);
    }

//some other part of app:
    ArrayList<? super ProxyHost> list;
            ProxyHost proxy;
            switch (type) {
            case "HTTP":
                proxy = new HttpProxyHost();
                processRow(row,proxy,httpProxies); // argument missmatch
                break;
            case "HTTPS":
                proxy = new HttpsProxyHost();
                processRow(row,proxy,httpsProxies); //argument missmatch
                break;
            case "SOCKS4":
                list = socks4Proxies; //lists type mismatch
                proxy = new Socks4ProxyHost();
                break;
            case "SOCKS5":
                list = socks5Proxies; //lists type mismatch
                proxy = new Socks5ProxyHost();
                break;
}


因此,为了使这段代码保持干燥,然后再添加到concreet集合中,我想执行一些常见的操作。
如何使用泛型而不使用超类型和显式强制转换?有办法吗?

每次我认为我了解通用集合时,经过一段时间后,我发现我实际上不懂;(

编辑:我想出了现在可以想到的最优雅的解决方案:

private <T extends ProxyHost> void processRow(Element row, T h, List<T> list) {
    h.setIp(row.child(0).text());
    h.setPort(Integer.parseInt(row.child(1).text()));
    h.setOrigin("SomeOrigin");
    list.add(h);
}
//and calls:
processRow(row, new HttpProxyHost(), httpProxies);
processRow(row, new HttpsProxyHost(), httpsProxies);
//etc works like charm now

最佳答案

为了使processRow(row,proxy,httpProxies)工作,T必须解析为HttpProxyHost,否则参数ArrayList<T> httpProxies将与类型httpProxiesArrayList<HttpProxyHost>值不兼容。

但是,如果THttpProxyHost,则参数T h需要一个HttpProxyHost,但该值实际上是类型为proxyProxyHost,即使该值实际上包含类型为HttpProxyHost的对象。

通过将new HttpProxyHost()分配给ProxyHost proxy,您失去了调用工作所需的兼容性。

你需要:

case "HTTP": {
    HttpProxyHost httpProxy = new HttpProxyHost();
    processRow(row, httpProxy, httpProxies);
    proxy = httpProxy;
    break;
}

10-06 01:15