让我们拥有超类ProxyHost
和扩展类HttpProxyHost
,HttpsProxyHosts
,Socks4ProxyHost
,Socks5ProxyHost
让我们在这些秘诀类上有几个集合:
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
将与类型httpProxies
的ArrayList<HttpProxyHost>
值不兼容。
但是,如果T
是HttpProxyHost
,则参数T h
需要一个HttpProxyHost
,但该值实际上是类型为proxy
的ProxyHost
,即使该值实际上包含类型为HttpProxyHost
的对象。
通过将new HttpProxyHost()
分配给ProxyHost proxy
,您失去了调用工作所需的兼容性。
你需要:
case "HTTP": {
HttpProxyHost httpProxy = new HttpProxyHost();
processRow(row, httpProxy, httpProxies);
proxy = httpProxy;
break;
}