我有以下定义:
public interface MessageResponseHandler<T extends MessageBody> {
public void responsed(Message<T> msg);
}
public class DeviceClientHelper {
public MessageResponseHandler<? extends MessageBody> messageHandler;
setHandler(MessageResponseHandler<? extends MessageBody> h){
this.messageHandler = h;
}
public someMethod(Object message){
Message<? extends MessageBody> msg = (Message<? extends MessageBody>) message;
if (this.messageHandler != null) {
this.messageHandler.responsed(msg);
}
}
}
我无法弄清楚为什么在someMethod()方法中调用
this.messageHandler.responsed(msg);
会在eclipse中给我一个有线编译器错误。类似的东西:
the method responsed(Message<capture#3-of ? extends MessageBody>) in
the type MessageResponseHandler<capture#3-of ? extends MessageBody> is
not applicable for the arguments (Message<capture#4-of ? extends
MessageBody>)
什么是&#34; catpure&#34;意味着在错误消息中?
答案 0 :(得分:8)
您说DeviceClientHelper
对messageHandler
的某些子类有MessageBody
。 someMethod
还为MessageBody
的某些子类提供了一条消息。但是,没有什么要求它们成为MessageBody
的相同子类,因此对responsed
的调用无效。
要使它们使用相同的子类,请在DeviceClientHelper
的特定子类上创建MessageBody
泛型,如下所示:
interface MessageResponseHandler<T extends MessageBody> {
public void responsed(Message<T> msg);
}
public class DeviceClientHelper<T extends MessageBody> {
public MessageResponseHandler<T> messageHandler;
void setHandler(MessageResponseHandler<T> h){
this.messageHandler = h;
}
public void someMethod(Object message){
Message<T> msg = (Message<T>) message;
if (this.messageHandler != null) {
this.messageHandler.responsed(msg);
}
}
}
但是,您的MessageResponseHandler
界面可能不需要关心MessageBody
类。这取决于它实际使用的方式,但这样的事情可能会更好:
interface MessageResponseHandler {
public void responsed(Message<? extends MessageBody> msg);
}
然后,您可以从messageHandler
字段中删除通用类型,并保留原始的someMethod
实现。
答案 1 :(得分:1)
这是使用泛型时常见的陷阱;尽管你的messageHandler和msg对象看起来是相同的,但它们确实不是(或者更确切地说,它们不一定非必须)。考虑一下:
class M1 extends MessageBody { ... }
class M2 extends MessageBody { ... }
MessageHandler<? extends MessageBody> handler = new MessageHandler<M1>();
/* So far so good */
Message<? extends MessageBody> message = new M2();
/* Still OK */
handler.responded(message);
/* Huh... you don't want to allow this, right? */
如果您的处理程序只能处理一种特定类型的邮件,那么您的DeviceClientHelper也应该只接收此特定类型的邮件,对吧?这样的事情怎么样?
public class DeviceClientHelper<T extends MessageBody> {
public MessageResponseHandler<T> messageHandler;
setHandler(MessageResponseHandler<T> h){
this.messageHandler = h;
}
public someMethod(Object message){
Message<T> msg = (Message<T>) message;
if (this.messageHandler != null) {
this.messageHandler.responsed(msg);
}
}
}
(这很可能会产生关于未经检查的演员的警告)
或者更好:
public class DeviceClientHelper<T extends MessageBody> {
public MessageResponseHandler<T> messageHandler;
setHandler(MessageResponseHandler<T> h){
this.messageHandler = h;
}
public someMethod(T message){
if (this.messageHandler != null) {
this.messageHandler.responsed(message);
}
}
}
如果你的DeviceClientHelper应该包含处理不同类型消息的处理程序(例如,它最初包含M1的处理程序,但是你为M2分配了一个处理程序),你仍然希望它由泛型验证,我我怕你运气不好这需要在运行时而不是编译时间检查泛型,并且由于泛型类型擦除,Java不支持它。
答案 2 :(得分:0)
这是由于泛型中的wildcard (?)
行为造成的。长话短说,用通配符键入的变量/参数不能分配给。
在您的代码中,调用this.messageHandler.responsed(msg)
会尝试将msg
传递给类型为? extends MessageBody
的参数。您正在使用的实际参数也是通配符类型并不重要:只要实际参数是通配符类型,您就无法将值传递给它。