在使用 Google Guava 优秀的 Multimap 时,我遇到了一些泛型问题。我有一个这样定义的类型处理程序
public interface Handler<T extends Serializable> {
void handle(T t);
}
在另一个类中我定义了一个多重映射,它将字符串映射到处理程序集合。
private Multimap<String, Handler<? extends Serializable>> multimap =
ArrayListMultimap.create();
现在,当我尝试使用多重映射进行操作时,我遇到了编译器错误。我的第一次尝试如下所示:
public <T extends Serializable> void doStuff1(String s, T t) {
Collection<Handler<T>> collection = multimap.get(s);
for (Handler<T> handler : collection) {
handler.handle(t);
}
}
这导致了以下错误。
类型不匹配:无法从 Collection>
到 Collection>
之后,我尝试像这样编码
public void doStuff2(String s, Serializable serializable) {
Collection<Handler<? extends Serializable>> collection = multimap.get(s);
for (Handler<? extends Serializable> handler : collection) {
handler.handle(serializable);
}
}
,不幸的是也失败了:
The method handle(capture#1-of ? extends Serialized) in the type
处理程序不适用于参数
(可序列化)
任何帮助将不胜感激。谢谢。
更新:
我设法解决此问题的唯一方法是抑制编译器警告。给定以下处理程序:
public interface Handler<T extends Event> {
void handle(T t);
Class<T> getType();
}
我可以这样编写事件总线。
public class EventBus {
private Multimap<Class<?>, Handler<?>> multimap = ArrayListMultimap.create();
public <T extends Event> void subscribe(Handler<T> handler) {
multimap.put(handler.getType(), handler);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void publish(Event event) {
Collection<Handler<?>> collection = multimap.get(event.getClass());
for (Handler handler : collection) {
handler.handle(event);
}
}
}
我想没有办法用更少甚至没有@SuppressWarnings 来处理这个问题?
I'm facing some problems with Generics when using Google Guava's excellent Multimap. I have a type Handler defined as such
public interface Handler<T extends Serializable> {
void handle(T t);
}
In another class I've defined a multimap that maps a String to a collection of Handlers.
private Multimap<String, Handler<? extends Serializable>> multimap =
ArrayListMultimap.create();
Now when I try to do stuff with the multimap, I'm getting compiler errors. My first attempt looked like this:
public <T extends Serializable> void doStuff1(String s, T t) {
Collection<Handler<T>> collection = multimap.get(s);
for (Handler<T> handler : collection) {
handler.handle(t);
}
}
which resulted in the following error.
Type mismatch: cannot convert from Collection<Handler<? extends Serializable>>
to Collection<Handler<T>>
Afterwards, I tried to code it like this
public void doStuff2(String s, Serializable serializable) {
Collection<Handler<? extends Serializable>> collection = multimap.get(s);
for (Handler<? extends Serializable> handler : collection) {
handler.handle(serializable);
}
}
which unfortunately failed as well:
The method handle(capture#1-of ? extends Serializable) in the type
Handler<capture#1-of ? extends Serializable> is not applicable for the arguments
(Serializable)
Any help would be greatly appreciated. Thanks.
Update:
The only way I have managed to fix this is by suppressing compiler warnings. Given the following handler:
public interface Handler<T extends Event> {
void handle(T t);
Class<T> getType();
}
I can write the event bus as such.
public class EventBus {
private Multimap<Class<?>, Handler<?>> multimap = ArrayListMultimap.create();
public <T extends Event> void subscribe(Handler<T> handler) {
multimap.put(handler.getType(), handler);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void publish(Event event) {
Collection<Handler<?>> collection = multimap.get(event.getClass());
for (Handler handler : collection) {
handler.handle(event);
}
}
}
I guess there's no way to handle this with less or even without @SuppressWarnings?
发布评论
评论(4)
问题是类型可能不同:
不允许您向多重映射添加任何内容,因为您不知道> 并尝试添加一个
?
实际代表什么。例如,您可以拥有一个 MultimapInteger
,因为两者都实现了Serialized
。编辑:其实上面这段话有一点错误。您应该能够将处理程序添加到多重映射,但由于处理程序的类型参数未知,因此您将无法使用处理程序,请参见下文。
在您的 doStuff1 方法中,您定义了一个具体参数 T,它可能是完全不同的东西。因此,编译器无法确定此分配是否正确:Collection> collection = multimap.get(s); (
T
真的是从多重映射中获得的处理程序的类型吗? - 编译器不知道)。您的第二种方法确实得到了正确的分配,但是
handle()
方法不起作用,因为您传入了一个Serialized
,它可以是任何东西 (String< /code>、
Integer
、其他),编译器仍然不知道处理程序的类型是否与该类型匹配(想象它是一个Handler
并且您传递了 <代码>字符串到doStuff2
)。您有多种替代方法可以解决这个问题,每种方法都有其自身的缺点:
Multimap>
,它允许您传递任何Serialized
对象到处理程序Multimap>
,这将限制您只能使用字符串处理The problem is that the types might be different:
wouldn't allow you to add anything to the multimap, since you don't know what
?
actually stands for. You could for example have aMultimap<String, Handler<String>>
and try to add anInteger
because both implementSerializable
.Edit: Actually the above paragraph is slightly wrong. You should be able to add handlers to the multimap, but since the type parameters of the handlers are not known, you wouldn't be able to use the handlers, see below.
In your
doStuff1
method you define a concrete parameterT
which might be something completely different. Thus the compiler can't determine if this assignment would be correct:Collection<Handler<T>> collection = multimap.get(s);
(isT
really the type of the handler you get from the multimap? - The compiler doesn't know).Your second approach does get the assignment right, however the
handle()
method won't work, since you pass in aSerializable
which could be anything (String
,Integer
, something else) and the compiler still doesn't know if the handler's type matches that (imagine it's aHandler<Number>
and you pass aString
todoStuff2
).You have several alternatives to fix that, each with it's own drawbacks:
Multimap<String, Handler<Serializable>>
, which would allow you to pass anySerializable
object to the handlerMultimap<String, Handler<String>>
, which would limit you to string handlers only如果您定义以下内容,效果会更好:
更新:问题的解释。
当您有类似 .. 之类的内容时,
这意味着 multimap 可以接受任何
Handler
其中N 扩展可序列化
。我们假设它将包含一个Handler
类型的值和一个Handler
类型的值。Foo
和Bar
不相关,也不相互扩展。当您在函数中想要使用类型来表示
Handler
,你试图表达一个同时是Foo
和Bar
的类型,但是不存在这样的类型。这解释了你的编译器问题。现在删除这个“-1”,如果您认为我是正确的,请投票给我的答案。
It will work better if you define:
Update: Explaination of your problem.
When you have something like ..
It means that multimap can accept ANY
Handler<N>
whereN Extends Serializable
. Let's consider that it will contain a value of typeHandler<Foo>
and a value of typeHandler<Bar>
.Foo
andBar
are unrelated and do not extend from each other.When in your function you want to use a type to represent the type of all the possible values of
Handler<? extends Serializable>
, you are trying to express a type which is at the same timeFoo
andBar
, but there is no such a type.This explains your problem with the compiler. Now remove this "-1" and vote for my answer if you think I am correct.
分两部分回答。首先,你的方法“消耗”对象,所以你不能使用“扩展”......你需要使用“超级”(PECS:生产者扩展,消费者超级!)。
在不更改处理程序的情况下,编译时不会对我发出警告:
通过这种方式,您可以定义从字符串到至少消耗 Serialized 的处理程序的多重映射。
其次,我经常使用与您的构造类似的东西:
返回的处理程序是 Class 的使用者。主要问题是,当您了解更多信息时,您无法“添加到泛型类型”...如果您需要,始终声明一个新变量可以将 @SuppressWarning 放在声明中:
这仅在您进行强制转换时才有效整个泛型类型。如果给你 Handler 并且你知道你所拥有的实际上是 Handler>,那么你可以转换它的唯一方法是通过原始类型:
如果你不这样做,你会得到一个错误而不是警告......
是的,泛型有点混乱..:-/
Two part answer. Firts, your method "consumes" objects, so you can't use "extends"... you need to use "super" (PECS: Producer Extends, Consumer Super!).
Without changing your handler, this compiles with without warnings for me:
This way you define a multimap from string to a handler that consume at least Serializable.
Second, I have often used something similar to your construct:
and is where the handler returned is a consumer of Class. The main problem is that you have no way to "add to the generic type" when you know more... If you need to, always declare a new variable can put the @SuppressWarning at the declaration:
This only work if you are casting the whole generic type. If you are given Handler and you know that what you have is really Handler>, the only way you can cast it is by going through the raw type:
If you don't, you get an error instead of a warning...
Yes, generics are kind of messy.. :-/
我稍微修改了你更新的代码。
现在它可以在没有@SuppressWarnings的情况下工作。
当然,我做了一些假设。
但我希望这会有所帮助。
修改后的EventBus。
还有一些代码,只是为了完成示例。
程序输出如下所示:
I modified your updated code a bit.
Now it works without @SuppressWarnings.
I've made some assumptions, of course.
But I hope it will be helpful.
Modified EventBus.
And some more code, just to complete the example.
The program output looks like this: