简体   繁体   中英

Java: Pass actual <T extends Event> class. (Generics Problems)

I've made my own EventExecutor class, which has the type <T extends Event> .

public interface EventExecutor<T extends Event> {

    ...
    public abstract void execute(Event event);
}

and I know right now that this up here is wrong, because I'm wanting to pass in:

public abstract void execute(T event);

I've been working on an Event Management System , and when an Event isn't cancelled after all other events have ran, certain code will run from the EventExecutor as shown:

// event parameter should be of type T.
EventManager.call(event -> {
    // code here.
}, Class<? extends Event>, Object... eventParameters);

The problem here is since the EventExecutor method execute has the parameter of Event , that means event -> is of type Event , and not the wanted class that extends Event , so that means I have to do some casting, which isn't what I want to do.

The problem that keeps me from using the generic type of T is my EventManager class's method call :

public static void call(EventExecutor<? extends Event> eventExecutor, Class<? extends Event> eventClass, Object... eventArgs) {
    synchronized (LOCK) {
        if (!checkIsEventClassRegistered(eventClass)) return;
        try {
            Event event = null;

            Class<?>[] constructorParameters = EventUtilities.getArrayOfClasses(eventArgs);
            Constructor<?> constructor = eventClass.getDeclaredConstructor(constructorParameters);

            event = (Event) constructor.newInstance(eventArgs);

            // HERE:
            if (!callAllRegisteredMethods(event)) eventExecutor.execute(event);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

I'll admit, I'm new to generics, and I don't see what's so wrong with everything. I've tried casting event (in the eventExecutor.execute(...) method) to T , but it tells me to create the method in EventExecutor called eventExecutor.execute(T) , but then EventExecutor throws an error, because it wants T to be a class that I create in the same package.

What am I doing wrong?

Edit
So basically, in the end I want to be able to not have to cast to my wanted Event class:

EventManager.call(event -> {
    // Have this automatically be recognized as an instance of MyEventClass?
    System.out.println(event.getText());
}, MyEventClass.class, new String("text"));

Can you make call a generic method?

public static <T extends Event> void call(
   EventExecutor<T> eventExecutor, Class<T> eventClass, Object... eventArgs) {
  synchronized (LOCK) {
    if (!checkIsEventClassRegistered(eventClass)) return;
    try {
      Class<?>[] constructorParameters = EventUtilities.getArrayOfClasses(
          eventArgs);
      Constructor<?> constructor = eventClass.getDeclaredConstructor(
          constructorParameters);

      T event = eventClass.cast(constructor.newInstance(eventArgs));

      if (!callAllRegisteredMethods(event)) eventExecutor.execute(event);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Note I replaced the cast to a call to Class.cast() .

Edit: The only reason why EventExecutor has to be generic is because you want to pass in an anonymous function/class to do the execution, and you want that function/class to depend on the actual type of the event. To avoid confusion, I would call it an EventCallback , since EventExecutor sounds similar to java.util.concurrent.Executor , so I was left wondering why you would want more than one.

Incidentally, it's probably not a good idea to call so much code that isn't under your control while you are in a synchronized block.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM