[英]Appropriate use of Java generics on collection
我以前从未有过使用泛型的机会(如编写泛型的类),但现在需要出现,而且我遇到了一些困惑。
有这个界面,这是一个东西的包装。 实现不是集合,因此,每个实例只能访问一个东西 。
public interface Resource<T> {
// Expected operations:
void write(ResourceState state);
ResourceState read();
}
作为实现,我希望有一个ExclusiveResource<T>
和一个ShareableResource<T>
,它们主要/仅在使用的锁定方案(分别为常规锁定和读写锁定)中有所不同。
至于如何read
和write
被执行,我打算使用的策略模式。
例如,我可能有
// This would implement a Strategy<File>.
FileStrategy fs = new FileStrategy();
Resource<File> r = new ExclusiveResource<File>(fs);
现在,我还有一些这些资源的集合 ,比如资源池。
我想将一个键映射到资源池中的每个资源,我想添加,检索和删除资源,但我不知道如何声明地图和方法。 我尝试过以下方法:
public class ResourcePool {
// instance variables
private final Map<String, Resource<?>> map;
/** Empty constructor of objects of class ResourcePool. */
public ResourcePool() {
map = new HashMap<String, Resource<?>>();
}
/** */
public Resource<?> get(String s) {
return map.get(s);
}
/** */
public void add(String s, Resource<?> r) {
map.put(s, r);
}
// ...
}
这似乎不是最合适的方式,并引用Josh Bloch,关于Effective Java Reloaded :
用户不必考虑使用通配符来使用您的API。
我用以下方法测试了这段代码:
public static void test() {
ResourcePool rp = new ResourcePool();
Resource<String> r1 = new ShareableResource<>("test");
Resource<Integer> r2 = new ShareableResource<>(1);
Resource<List<String>> r3 = new ShareableResource<>(
Arrays.asList(new String[]{"1", "2"})
);
// These are all ok.
rp.add("1", r1);
rp.add("2", r2);
rp.add("3", r3);
// This results in a compiler error (incompatible types).
Resource<String> g1 = rp.get("1");
// This results in a compiler warning (unsafe operation).
Resource<String> g2 = (Resource<String>) rp.get("1");
}
当代码编译警告时,我不喜欢它。 让我感到内疚,似乎暗示了糟糕的编码。
所以,我的问题是如何处理这种情况。
这是我正在做的事情的正确方法吗?
这可以通过没有不安全操作的方式完成吗?
我认为没有办法避免使用你的设计进行未经检查的演员。 也就是说,每次检索Resource
时都可以避免进行转换:
@SuppressWarnings("unchecked")
public <T> Resource<T> get(String s, Class<T> c) {
return (Resource<T>) map.get(s);
}
当您想要检索Resource
,您传入所需的类,如下所示:
Resource<String> g1 = rp.get("1", String.class);
但是,您应该小心这个设计,因为没有运行时保证返回的Resource
实际上是Resource<String>
。
您可以为所需的每种类型的资源创建不同的集合,并使ResourcePool
也是通用的:
ResourcePool<String> stringpool = new ResourcePool<String>();
ResourcePool<Integer> intpool = new ResourcePool<Integer>();
这将为您提供编译时检查类型的好处。 当你从ResourcePool
获得一些东西时,你似乎知道你想要什么类型,所以你可以选择合适的集合。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.