在 Java 中实现通用接口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4326017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implementing Generic Interface in Java
提问by whistlenuts
I have a Java generics question I was hoping someone could answer. Consider the following code:
我有一个 Java 泛型问题,希望有人能回答。考虑以下代码:
public interface Event{}
public class AddressChanged implements Event{}
public class AddressDiscarded implements Event{}
public interface Handles<T extends Event>{
public void handle(T event);
}
I want to implement this Handles interface like this:
我想像这样实现这个 Handles 接口:
public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{
public void handle(AddressChanged e){}
public void handle(AddressDiscarded e){}
}
But java doesn't allow implementing Handles twice using the Generic. I was able to accomplish this with C#, but cannot figure a workaround in java without using Reflection or instanceof and casting.
但是 java 不允许使用泛型实现两次句柄。我能够使用 C# 完成此操作,但无法在不使用 Reflection 或 instanceof 和强制转换的情况下在 java 中找到解决方法。
Is there a way in java to implement the Handles interface using both generic interfaces? Or perhaps another way to write the Handles interface so the end result can be accomplished?
java中有没有办法使用通用接口来实现 Handles 接口?或者也许是另一种编写 Handles 接口的方法,以便可以完成最终结果?
采纳答案by Amir Raminfar
You can't do that in Java. You can only implement one concrete realization of the same generic interface. I would do this instead:
你不能在 Java 中做到这一点。您只能实现相同通用接口的一种具体实现。我会这样做:
public class AddressHandler implements Handles<Event>{
public void handle(Event e){
if(e instanceof AddressDiscarded){
handleDiscarded(e);
} else if(e instanceof AddressChanged){
handleChanged(e);
}
}
public void handleDiscarded(AddressDiscarded e){}
public void handleChanged(AddressChanged e){}
}
回答by Daniel Schneller
AFAIK you cannot do that, because when compiling the source code in Java these will both boil down to handle(Event)
, making the method ambiguous.
AFAIK 你不能这样做,因为在 Java 中编译源代码时,这些都将归结为handle(Event)
,使方法模棱两可。
The generic information is not available during runtime in Java, in contrast to C#. That is why there it works as you describe.
与 C# 相比,Java 在运行时无法使用通用信息。这就是为什么它像你描述的那样工作。
You will have to change the method names to make them unique, like handleAddressChanged
and handleAddressDiscarded
.
您必须更改方法名称以使其唯一,例如handleAddressChanged
和handleAddressDiscarded
。
This is indeed one of the weak points of Java generics.
这确实是 Java 泛型的弱点之一。
回答by cdhowie
No, because different "concrete" generic types in Java compile to the same type. The actual interface your object will implement is:
不,因为 Java 中不同的“具体”泛型类型编译为相同的类型。您的对象将实现的实际接口是:
public interface Handles {
public void handle(Event event);
}
And, obviously, you can't have two different methods with an identical signature...
而且,显然,您不能有两种具有相同签名的不同方法......
回答by Stan Kurilin
Going after @Amir Raminfar, you can use visitor pattern
在@Amir Raminfar 之后,您可以使用访问者模式
interface Event{
void accept(Visitor v);
}
interface Visitor {
void visitAddressChanged(AddressChanged a);
void visitAddressDiscarded(AddressDiscarded a);
}
class AddressChanged implements Event{
@Override
public void accept(Visitor v) {
v.visitAddressChanged(this);
}
}
class AddressDiscarded implements Event{
@Override
public void accept(Visitor v) {
v.visitAddressDiscarded(this);
}
}
class AddressHandler implements Visitor {
void handle(Event e){
e.accept(this);
}
public void visitAddressChanged(AddressChanged e){}
public void visitAddressDiscarded(AddressDiscarded e){}
}
回答by Aaron Digulla
Unfortunately not. The usual solution (fat, ugly, fast) is to create one Handles
interface (i.e. HandlesAddressChange
, HandlesAddressDiscarded
) and give each of them a different method (handleAddressChange(...)
, handleAddressDiscarded()
).
不幸的是没有。通常的解决方案(胖、丑、快)是创建一个Handles
接口(即HandlesAddressChange
, HandlesAddressDiscarded
)并为每个接口提供不同的方法(handleAddressChange(...)
, handleAddressDiscarded()
)。
That way, the Java runtime can tell them apart.
这样,Java 运行时就可以将它们区分开来。
Or you can use anonymous classes.
或者您可以使用匿名类。
回答by Andreas Dolk
It isn't allowed because Java erases generic signatures during compilation. The interface method will actually have the signature
这是不允许的,因为 Java 在编译期间会擦除通用签名。接口方法实际上会有签名
public void handle(Object event);
So you have two choices. Either implement separate Handlers for different events:
所以你有两个选择。要么为不同的事件实现单独的处理程序:
public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ }
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ }
or implement one handler for all but check the type of the incoming event:
或者为所有人实现一个处理程序,但检查传入事件的类型:
public void handle(Event e){
if (e instanceof AddressChanged) {
handleAdressChanged(e);
}
else if (e instanceof AddressDiscareded) {
handleAdressDiscarded(e);
}
}
回答by Olivier Heidemann
An implementation like this won't work due to the constraints of the java specification. But if you're not afraid to use AOP or some sort of an IOC-Container you could use annotations for that. Than your Aspects or the container could manage the messaging infrastructure and call the methods you annotate.
由于 Java 规范的限制,这样的实现将无法工作。但是,如果您不害怕使用 AOP 或某种 IOC-Container,您可以为此使用注释。比您的方面或容器可以管理消息传递基础结构并调用您注释的方法。
First you have to create the annotations.
首先,您必须创建注释。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventConsumer {}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Handles{}
The you may annotate your class like that:
你可以像这样注释你的类:
@EventConsumer
public class AddressHandler{
@Handles
public void handle(AddressChanged e){}
@Handles
public void handle(AddressDiscarded e){}
}