Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Java实现通用接口_Java_Generics_Cqrs - Fatal编程技术网

用Java实现通用接口

用Java实现通用接口,java,generics,cqrs,Java,Generics,Cqrs,我有一个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); } 公共接口事件{} 公共类

我有一个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);
}
公共接口事件{}
公共类AddressChanged实现事件{}
公共类AddressDiscarded实现事件{}
公共接口句柄{
公共无效句柄(T事件);
}
我想实现如下处理接口:

public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{
    public void handle(AddressChanged e){}
    public void handle(AddressDiscarded e){}
}
公共类AddressHandler实现句柄,句柄{
公共无效句柄(地址已更改){}
公共无效句柄(地址){}
}
但是java不允许使用泛型实现两次句柄。我可以用C#完成这一点,但如果不使用反射或instanceof and casting,我就无法在java中找到解决方法


java中有没有一种方法可以使用两个通用接口来实现Handles接口?或者用另一种方法编写Handles接口,以实现最终结果?

在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){}
}
公共类AddressHandler实现句柄{
公共无效句柄(事件e){
如果(地址的实例已丢弃){
已处理的文件(e);
}否则,如果(地址更改的实例){
改变手柄(e);
}
}
已处理的公共无效已存档(地址e){}
公共无效句柄已更改(地址已更改){}
}

AFAIK您不能这样做,因为在Java中编译源代码时,这两种方法都会归结为
处理(事件)
,使得方法不明确

与C#相比,Java中的通用信息在运行时不可用。这就是为什么它能像你描述的那样工作

您必须更改方法名称以使其唯一,如
handleAddressChanged
handleAddressDiscarded

这确实是Java泛型的弱点之一。

不,因为Java中不同的“具体”泛型类型编译为相同的类型。对象将实现的实际接口是:

public interface Handles {
    public void handle(Event event);
}

而且,很明显,不能有两个具有相同签名的不同方法…

在@Amir Raminfar之后,可以使用模式


不幸的是没有。通常的解决方案(胖、丑、快)是创建一个
句柄
接口(即
HandlesAddressChange
HandlesAddressDiscarded
),并为每个句柄提供不同的方法(
HandledAddressChange(…)
HandledAddressDiscarded()

这样,Java运行时就可以将它们区分开来


或者您可以使用匿名类。

这是不允许的,因为Java在编译过程中会擦除通用签名。接口方法将实际具有签名

public void handle(Object event);
所以你有两个选择。为不同的事件实现不同的处理程序:

public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ }
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ }

由于java规范的限制,这样的实现无法工作。 但是,如果您不怕使用AOP或某种IOC容器,您可以使用注释。您的方面或容器可以管理消息传递基础结构并调用您注释的方法

首先,您必须创建注释

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventConsumer {}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Handles{}
您可以这样注释您的类:

@EventConsumer
public class AddressHandler{
    @Handles
    public void handle(AddressChanged e){}
    @Handles
    public void handle(AddressDiscarded e){}
}

这是有争议的。。。这个“级联实例”是一个非常程序化的范例。当然可以,但我觉得不是很好的风格。但因此,使用不同的方法名称也可能不是完美的,这可能是一个品味问题。这就是我要做的。您不必:)@don:但同一个泛型接口的多个实例不是这样的。这就是我们要说的实际上,擦除将是
公共无效句柄(事件)+1,但在模式中,事件“接受”访问者,访问者“访问”事件:)@robev,我忘了在那一行重命名它。谢谢修正了。这确实是一个编译时问题。您不需要知道对象的运行时属性(参数甚至可以是
null
!)来区分方法。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventConsumer {}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Handles{}
@EventConsumer
public class AddressHandler{
    @Handles
    public void handle(AddressChanged e){}
    @Handles
    public void handle(AddressDiscarded e){}
}