以下是我想在我的java代码中编写的内容:
private <A extends Action<R>, R extends Result> MyType<A,R> member;
Run Code Online (Sandbox Code Playgroud)
然而,这是无效的语法.所以我最终写作:
private MyType<? extends Action<? extends Result>, ? extends Result> member;
Run Code Online (Sandbox Code Playgroud)
但是这忽略了两个派生的类Result都相同的事实.我的类方法都强制执行这种关系,因此我可以确定MyType强制执行它,但member在某些情况下我仍然需要进行不安全的类型转换.
这是我想要做的精确版本,虽然它更加危险:
我希望我能做到:
private <A extends Action<R>, R extends Result>
Map< Class<A>, ActionHandler<A,R> > handlers;
Run Code Online (Sandbox Code Playgroud)
相反,我必须这样做:
private Map< Class< ? extends Action<? extends Result> >,
ActionHandler<? extends Action<? extends Result>,
? extends Result> > handlers;
Run Code Online (Sandbox Code Playgroud)
我的方法强制执行所需的关系,看起来像这样:
public <A extends Action<R>, R extends Result> void addHandler(
ActionHandler<A, R> handler ) {
handlers.put( handler.getActionType(), handler );
}
Run Code Online (Sandbox Code Playgroud)
我想要以下方法:
public <A extends Action<R>, R extends Result> ActionHandler<A, R>
findHandler( A action ) {
return handlers.get( action.getClass() );
}
Run Code Online (Sandbox Code Playgroud)
但这不起作用:我必须添加一个演员和一个@SuppressWarnings("unchecked").
我尝试为此目的创建一个新类:
public class MyMap <A extends Action<R>, R extends Result> extends
HashMap< Class<A>, ActionHandler<A,R> > { ... }
MyMap< ?, ? > handlers;
Run Code Online (Sandbox Code Playgroud)
但它没有用,我还需要演员.
没有干净的方法可以做到这一点。你能做的最好的就是你已经做过的——隐藏Map强制类型安全的后面方法,并隐藏这些方法中必要的强制转换。
来自《Effective Java》第 2 版,第 29 条:“考虑类型安全的异构容器”(其中 Josh Bloch 勾勒出您正在做的事情的一个简单版本,一个“映射”,其中键是类,值是键类的实例):
接下来要注意的是,
favoritesMap 的值类型很简单Object。换句话说,Map不保证键和值之间的类型关系。事实上,Java 的类型系统还不足以表达这一点。但我们知道这是真的,当需要检索最喜欢的东西时,我们会利用它。
鉴于无论如何您都无法对值进行任何有用的类型强制,最不混乱的实现可能是这样的:
public class HandlerRegistry
{
private Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
public <R extends Result, A extends Action<R>>
void addHandler(Class<A> actionClass, ActionHandler<R, A> handler) {
map.put(actionClass, handler);
}
@SuppressWarnings("unchecked")
public <R extends Result, A extends Action<R>> ActionHandler<R, A>
findHandler(A action) {
return (ActionHandler<R, A>) map.get(action.getClass());
}
}
Run Code Online (Sandbox Code Playgroud)
关于基于 - 的解决方案需要注意的一件事Map:如果action不完全是用作键的类,map.get()则不会起作用 - 例如,如果它是一个子类,或者如果键类是一个接口而其action本身是实施。您可能会更好:
@SuppressWarnings("unchecked")
public <R extends Result, A extends Action<R>> ActionHandler<R, ? super A>
findHandler( A action ) {
for ( Map.Entry<Class<?>, Object> entry : map.entrySet() )
{
if (entry.getKey().isAssignableFrom(action.getClass())) {
return (ActionHandler<R, ? super A>) entry.getValue();
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
(注意:最初上面的第二个例子返回了ActionHandler<R, A>,这实际上是不正确的——它应该是? super A。(我们不知道它还能处理什么A——它可以是 的任何超类A,一直到Object。)在这种特殊情况下,它可能足够安全,但如果你考虑像 a 这样的东西List,我们可能会遇到很多麻烦:你可以安全地将 an 放入Aa 中List<? super A>,但如果你假设你只会A从中得到 s ,那么你将会得到ClassCastExceptions。)