我正在考虑将此 C# 库移植到 Java 和 Android
我想移植这个接口(interface)
public interface IHandle<in T> where T : class
{
void Handle(T message);
}
它需要处理逆变,以便它可以处理像 IHandle<ISomeIntefaceOrBaseClass>
这样的消息等等
库的用户可以添加订阅者,当收到消息时,我会检查处理程序正在执行的操作
subscribers
.OfType<IHandle<T>>();
这对于 Java 泛型来说是可能的,还是有更多的“Java 方式”来做到这一点?
最佳答案
我假设是 subscribers.OfType<IHandle<T>>();
您想要获取类型为 IHandle<T>
的所有订阅者哪里T
是消息的类型,对吗?
在 Java 中,您必须稍微更改代码,因为由于类型删除,您无法提供这样的类型。
假设每个类型/类都有一个句柄,您可以执行以下操作:
interface IHandle<T> {
Class<T> getMessageType(); //needed to query the handle for the supported class
void handle( T message );
}
要创建该接口(interface)的实现,您有多种选择:
为每个类创建一个实现:
class SpecialMessageHandle implements IHandle<SpecialMessage> {
public Class<SpecialMessage> getMessageType() { return SpecialMessage.class; }
public handle( SpecialMessage message ) { ... }
}
或者将类作为参数传递:
class Handle<T> implements IHandle<T> {
Class<T> messageClass;
public Handle( Class<T> msgClass ) { messageClass = msgClass; }
public Class<T> getMessageType() { return messageClass; }
public handle( T message ) { ... }
}
然后,您可能会有一个映射消息类来处理订阅者的类和处理类(例如 Guava Multimap):
Map<Class<?>, IHandle<?>> handles = ...;
Multimap<IHandle<?>, Subscriber> subscribers = ...;
请注意,我使用 Class<?>
在这里,因为我不知道这些类是否有一个共同的父类(super class)或接口(interface)。如果你有一个共同的父类(super class)或接口(interface)X
那么你会使用Class<? extends X>
相反。
另外请注意,我使用了 IHandle<?>
因为在Java中你不能以键和值需要使用相同泛型类型同时支持不同键的方式定义映射,即你不能这样做 Map<Class<T>, IHandle<T>>
其中每个 key 都是不同的 T
但只允许符合该键的值。
添加句柄如下所示:
handles.put( handle.getMessageType(), handle );
使用消息查询该 map 将像这样工作:
IHandle<?> handle = handles.get( message.getClass() );
Collection<Subscriber> handleSubscribers = subscribers.get( handle );
请注意,如果您还想获取父类(super class)的订阅者(例如,如果 SpecialMessage extends Message
并且您还想获取订阅 Message
的订阅者),那么您需要沿着类层次结构向上走.
以下是您升级一个所需要做的事情:
handles.get( message.getClass().getSuperclass() );
for( Class<?> interface : message.getClass().getInterfaces() ) {
handles.get( message );
}
关于java - Java中的逆变类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25623049/