Java泛型-类型不重要

Java泛型-类型不重要,java,generics,raw-types,Java,Generics,Raw Types,(为标题感到抱歉,我想不出更好的了) 我正在做一个大项目,里面充满了对原始类型的引用,我正试图摆脱它们。 问题是,在大多数情况下,我们并不知道实际的类型。 举个例子也许是最好的解释方式 考虑: public interface Event<S, D> { S getSource(); D getData(); } public interface Listener<E extends Event<?, ?>> { void onEvent(E e

(为标题感到抱歉,我想不出更好的了)

我正在做一个大项目,里面充满了对原始类型的引用,我正试图摆脱它们。 问题是,在大多数情况下,我们并不知道实际的类型。 举个例子也许是最好的解释方式

考虑:

public interface Event<S, D> {
  S getSource();
  D getData();
}

public interface Listener<E extends Event<?, ?>> {
  void onEvent(E event);
}

public interface Listenable<E extends Event<?, ?>> {
  void addListener(Listener<E> listener);
  void removeListener(Listener<E> listener);
}

public class DataAccess implements Listenable {

  ...

  public void addListener(final Listener listener) {
    eventHandler.addListener(listener);
  }

  public void removeListener(final Listener listener) {
    eventHandler.removeListener(listener);
  }
}
公共接口事件{
S getSource();
D getData();
}
公共接口侦听器>{
void addListener(Listener-Listener);
无效RemovelListener(侦听器);
}
公共类DataAccess实现了Listenable{
...
公共void addListener(最终侦听器){
addListener(监听器);
}
公共void RemovelListener(最终侦听器){
RemovelListener(侦听器);
}
}
DataAccess并不真正关心我们传入的侦听器的类型,因为它可以接收不同类型的事件。我怀疑这里使用泛型的方式不对,可能Listener和Listenable不需要泛型

我想把听众换成听众

public interface Listener {
  void onEvent(Class<? extends Event<?, ?>> event);
}    
公共接口侦听器{
作废事件(类别>事件);
}    
但OneEvent将无法访问事件的方法


我遗漏了什么吗?

如果我是你,我会在接口中尽可能保持最通用的,我会让实现定义显式类型,否则如果在接口中你只使用通配符,你就不能再从实现中的泛型功能中获益了

所以我想要这样的东西

public interface Event<S, D> {
    S getSource();
    D getData();
}

public interface Listener<E extends Event<S, D>, S, D> {
    void onEvent(E event);
}

public interface Listenable<E extends Event<S, D>, S, D> {
    void addListener(Listener<E, S, D> listener);
    void removeListener(Listener<E, S, D> listener);
}
公共接口事件{
S getSource();
D getData();
}
公共接口侦听器{
无效事件(E事件);
}
可侦听的公共接口{
void addListener(Listener-Listener);
无效RemovelListener(侦听器);
}

由于这种更加灵活的方法,如果您有接受特定事件的实现,那么您可以缩小允许事件的类型,否则您仍然可以使用通配符来支持任何事件。

如果我是您,我将在接口中尽可能保持最通用,如果您只在接口中使用,我将让实现定义显式类型通配符在您的实现中不能再利用泛型的强大功能了

所以我想要这样的东西

public interface Event<S, D> {
    S getSource();
    D getData();
}

public interface Listener<E extends Event<S, D>, S, D> {
    void onEvent(E event);
}

public interface Listenable<E extends Event<S, D>, S, D> {
    void addListener(Listener<E, S, D> listener);
    void removeListener(Listener<E, S, D> listener);
}
公共接口事件{
S getSource();
D getData();
}
公共接口侦听器{
无效事件(E事件);
}
可侦听的公共接口{
void addListener(Listener-Listener);
无效RemovelListener(侦听器);
}
由于这种更灵活的方法,如果您的实现接受特定事件,那么您可以缩小允许事件的类型,否则您仍然可以使用通配符支持任何事件。

为什么不:

public class DataAccess implements Listenable<Event<?,?>>
    {


          private Listenable<Event<?, ?>> eventHandler;

          public void addListener(final Listener<Event<?,?>> listener) 
          {
            eventHandler.addListener(listener);
          }

          public void removeListener(final Listener<Event<?,?>> listener) 
          {
            eventHandler.removeListener(listener);
          }

    }
为什么不:

public class DataAccess implements Listenable<Event<?,?>>
    {


          private Listenable<Event<?, ?>> eventHandler;

          public void addListener(final Listener<Event<?,?>> listener) 
          {
            eventHandler.addListener(listener);
          }

          public void removeListener(final Listener<Event<?,?>> listener) 
          {
            eventHandler.removeListener(listener);
          }

    }

如果
Listener
可以处理任何类型的事件,那么正确的定义方法是:

public interface Listener {
  void onEvent(Event<?, ?> event);
}
公共接口侦听器{
无效事件(事件);
}
然后,您可以在
onEvent()
实现中调用
getSource()
getData()
,但它们将返回类型为
Object
的值,您可能需要执行一些强制转换,以便在侦听器中执行任何有用的操作


事实上,听众可以处理任何类型的事件,这使得整个S&D通用性变得毫无意义@NicolasFilotto的回答显示了声音设计应该是什么样子,但也许你没有太多选择。

如果
监听器可以处理任何类型的事件,那么正确的定义方式是:

public interface Listener {
  void onEvent(Event<?, ?> event);
}
公共接口侦听器{
无效事件(事件);
}
然后,您可以在
onEvent()
实现中调用
getSource()
getData()
,但它们将返回类型为
Object
的值,您可能需要执行一些强制转换,以便在侦听器中执行任何有用的操作


事实上,听众可以处理任何类型的事件,这使得整个S&D通用性变得毫无意义@NicolasFilotto的回答显示了声音设计应该是什么样子,但可能您没有太多选择。

鉴于当前的声明,我可以编写以下内容,而不会受到编译器的反对:

void example(DataAccess eventSource) {
    abstract class MyEvent implements Event<BigInteger,String>{}
    eventSource.addListener(new Listener<MyEvent>() {
        public void onEvent(MyEvent event) {
            BigInteger bi=event.getSource();
            String str=event.getData();
        }
    });
}
void示例(DataAccess事件源){
抽象类MyEvent实现事件{}
addListener(新的Listener(){
public void onEvent(MyEvent事件){
BigInteger bi=event.getSource();
String str=event.getData();
}
});
}
不仅很难想象事件源会适当地传递预期的事件类型,而且它甚至没有足够的信息来决定永远不调用该侦听器,因为找到预期类型的唯一方法是反射,这在泛型类型方面有一些限制

结论是你不能提供这样的灵活性。通常,事件源应该知道它可以传递什么类型的事件。在这种情况下,它应该声明如下:

public class DataAccessEvent implements Event<DataAccess,SpecificDataType> {
  public DataAccess getSource() {
    // ...
  }
  public SpecificDataType getData() {
    // ...
  }
}
public class DataAccess implements Listenable<DataAccessEvent> {

  public void addListener(Listener<DataAccessEvent> listener) {
    eventHandler.addListener(listener);
  }

  public void removeListener(Listener<DataAccessEvent> listener) {
    eventHandler.removeListener(listener);
  }
}
公共类DataAccessEvent实现事件{
公共数据访问getSource(){
// ...
}
public SpecificDataType getData(){
// ...
}
}
公共类DataAccess实现了Listenable{
公共void addListener(侦听器侦听器){
addListener(监听器);
}
公共void RemovelListener(侦听器侦听器){
RemovelListener(侦听器);
}
}
注意,由于类声明,现在需要正确的方法签名。为源永远不会传递的事件类型注册侦听器是没有意义的


也可以在不导出实际事件类型的情况下执行相同操作,例如

public class DataAccess implements Listenable<Event<DataAccess,SpecificDataType>> {

  public void addListener(Listener<Event<DataAccess,SpecificDataType>> listener) {
    eventHandler.addListener(listener);
  }

  public void removeListener(Listener<Event<DataAccess,SpecificDataType>> listener) {
    eventHandler.removeListener(listener);
  }
}
public类DataAccess实现了Listenable{
公共void addListener(侦听器侦听器){
addListener(监听器);
}
公共void RemovelListener(侦听器侦听器){
RemovelListener(侦听器);
}
}

支持听众