我太近了,但我不会把头缠在上面。
我正在尝试使用默认的东西在Java(Android)中创建一个事件管理器,比如注册事件,引发事件等等......
我希望这是“通用的”,我可以这样编写:
StringChangedEvent event
= evManInst.Register<StringChangedEvent>(new StringChangedEvent());
event.Publish("Hello");
在另一个班级
StringChangedEvent event
= evManInst.Register<StringChangedEvent>(new StringChangedEvent());
event.Subscribe(this)
当然,实例应该是同一个。我必须传递这个对象,因为我不能使用新的T() - 但也许我在这里做了一些非常邪恶的泛型: - )
如果您阅读了我的EventManager的实现,第一个返回行将不会编译,因为类型不兼容。我该如何解决这个问题?有趣的是,如果你看一下代码,它的类型一切都很好,没有什么可以出错(在我看来)。
还有一点:我不想创建泛型 EventManager<StringChangedEvent>
,因为这会将此EventManager限制为一种类型的事件。并且返回EventBase
并将其转换为丑陋(但也许是唯一可行的方法?)。
public class EventManager
{
private HashMap<Class<EventBase>, EventBase> _registeredEvents
= new HashMap<Class<EventBase>, EventBase>();
public<T extends EventBase> T Register(T instance)
{
if (_registeredEvents.containsKey(instance.getClass()))
{
return _registeredEvents.get(instance.getClass());
}
else
{
return instance;
}
}
}
编辑澄清对Kaediil答案的评论
EventManager x = new EventManager<TestEvent>();
EventManager x2 = new EventManager();
// Not OK
TestEvent t = x.Register(new TestEvent());
// OK (but I want MORE :-)
TestEvent t2 = (TestEvent)x.Register(new TestEvent());
// This to be exact, because then I can do something like this
TestEvent t2 = x.Register<TestEvent>(new TestEvent());
x.Register<TestEvent>(new TestEvent()).CallMethodOfTestEvent();
答案 0 :(得分:1)
试试这个:
public class EventManager <T extends EventBase>{
private HashMap<Class<EventBase>, T > _registeredEvents
= new HashMap<Class<EventBase>, T>();
public T Register( T instance)
{
if (_registeredEvents.containsKey(instance.getClass()))
{
return _registeredEvents.get(instance.getClass());
}
else
{
return instance;
}
}
}
答案 1 :(得分:1)
以下代码应该执行您想要的操作:
import java.util.HashMap;
public class EventManager {
private HashMap<Class<? extends EventBase>, EventBase> _registeredEvents
= new HashMap<Class<? extends EventBase>, EventBase>();
public <T extends EventBase> T Register(T event) {
@SuppressWarnings("unchecked")
Class<? extends T> eventType = (Class<? extends T>) event.getClass();
if (_registeredEvents.containsKey(eventType)) {
return eventType.cast(_registeredEvents.get(eventType));
} else {
_registeredEvents.put(eventType, event);
return event;
}
}
}
class EventBase {}
class ChangeEvent extends EventBase {}
class Main {
public static void main(String[] args) {
EventManager em = new EventManager();
ChangeEvent e = em.Register(new ChangeEvent());
}
}
编译器抱怨@SuppressWarnings
之后的行,但我认为它应该是正确的,只是getClass()
周围的编译器魔法无法正确处理。
您的代码中的问题是,您无法从EventBase
检索除HashMap<…, EventBase>
之外的其他内容,因为无法静态证明这是类型安全的。你必须在某个地方施放,Class.cast
允许你在方法的实现中执行此操作。 (你也可以强制转换为T
以“让编译器闭嘴”,但这是一个坏主意,因为它会使用你的API而不是强制转换的代码在代码中发生ClassCastExceptions。)