Java: parameter subclass / subtype substitution when overriding a method?

So I asked this question before, but I had an error in the code that most people chose, not the problem itself.

In any case, I'm trying to override the interface method in the class. However, I want the parameter type in the overriding method to be a subclass of the parameter type, as defined in the override method.

Interface:

public interface Observer { public void update(ComponentUpdateEvent updateEvent) throws Exception; } 

While the class that overrides this method:

 public class ConsoleDrawer extends Drawer { //... @Override public void update(ConsoleUpdateEvent updateEvent) throws Exception { if (this.componentType != updateEvent.getComponentType()) { throw new Exception("ComponentType Mismatch."); } else { messages = updateEvent.getComponentState(); } } //... } 

ConsoleUpdateEvent is a subclass of ComponentUpdateEvent.

Now I could just use the update () method in ConsoleDrawer as the ComponentUpdateEvent parameter, and then pass it to ConsoleUpdateEvent, but if possible, I'm looking for a slightly more elegant solution. Anyhelp would be appreciated. Thanks.

+7
java override generics parameters subclass
source share
3 answers

You can not. This is not Eiffel. The problem is that you can use the interface to call an implementation method with an incompatible type. Therefore, covariant parameters are not allowed. Contravariant parameters are also not allowed, but it is easier to provide overload. The return type of Covariant is allowed (starting with 1.5).

You can parameterize the interface:

 public interface Observer<T extends ComponentEvent> { void update(T event) throws Exception; } 

Alternatively, use a more intuitive interface:

 public interface ConsoleObserver { void update(ConsoleEvent event) throws Exception; } 
+7
source share

You can try the following. @Deprecated issues a warning if the compiler knows that you will be calling the first method, not the second.

 @Override @Deprecated public void update(ComponentUpdateEvent updateEvent) { // throws a ClassCastException if its not the right type. update((ConsoleUpdateEvent) updateEvent); } public void update(ConsoleUpdateEvent updateEvent) { messages = updateEvent.getComponentState(); } 

By the way: You should not just throw an Exception at all. This, of course, is not the best practice.

EDIT: I applied another solution to this problem that works well with OSGi but can work anywhere.

An observer registers with a broker and expects to find methods with annotation, for example, ObserverCallback.

eg.

 public class ConsoleDrawer extends Drawer { @ObserverCallback public void onConsoleUpdateEvent(ConsoleUpdateEvent updateEvent) { messages = updateEvent.getComponentState(); } } public class DeviceDrawer extends Drawer { @ObserverCallback public void onDeviceUpdateEvent(DeviceUpdateEvent updateEvent) { // do something. } } 

In the first case, the broker finds a method with @ObserverCallback that takes one argument. This is the only type that the broker transmits. The second class expects a different type. Observers can have several methods / types allowing them to process different messages in different methods corresponding to this type. You also know that you will never get a data type that you do not expect.

+2
source share

Following the principles of OOP, a subclass should be used in the same way as a parent. eg

 Observer ob = new ConsoleDrawer(); ob.update(new ComponentUpdateEvent()); // This needs to work always. 

However, if Java allowed you to use the parameter subtype when overriding the method, then it will output your code in cases where the override method (in a subclass) rejected the input parameter (ComponentUpdateEvent in the above case). That way, you'll never be sure if it is safe to call update () or not in the Observer link.

Therefore, the only logical solution is to accept the parameter of the parent class, check its type, and then apply it to the required subtype.

+2
source share

All Articles