Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Override a Iterable<interface> return type method into Iterable<? extends interface> return type method

I have an interface that I need to implement. It looks something like this:

public interface SimulationState {
    ...
    public Iterable<VehicleStatus> getVehicleStatuses();
}

I am trying to extend the interface into some sort of a decorator interface as the following:

public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
    ...
    @Override
    public Iterable<V> getVehicleStatuses();
}

OR

public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
    ...
    @Override
    public Iterable<? extends VehicleStatus> getVehicleStatuses();
}

Here's the concrete class I'm implementing the interface at:

public class WareHouseState implements SimulationState {
    ...       
    @Override
    public Iterable<VehicleStatus> getVehicleStatuses() {
    return this.vStatuses;
   }
}

I am implementing the VehicleStatus interface at a class named VehicleState so i could return the implemented VehicleState though the Iterable in my concrete class

So at a class in my project I am calling the getVehicleStatuses() method and I am obligated to cast every element to VehicleState as the following:

public class Gate {
    ...
    private ArrayList<VehicleThread> vehicles;

    public Gate(WareHouse wareHouse, GatePriority priority) {
        ...
        this.vehicles = new ArrayList<>();
        wareHouseState.getVehicleStatuses().forEach(v -> vehicles.add(new VehicleThread((VehicleState) v, wareHouse)));
        sortSameTimeArrivalBy(priority);

    }
}

I know I am doing something wrong here, I was wondering if that way of implementation is allowed. Compiler tells me to change the method in the implemented interface and it's not applicable for my application has to work on a different framework.

I need to return a variety of concrete types that implements the same interface without having to cast every element.

like image 520
Saleem A. Khair Avatar asked Apr 15 '26 13:04

Saleem A. Khair


1 Answers

You can't, because when overriding you can only narrow down the return type, and neither Iterable<V> nor Iterable<? extends VehicleStatus> are subtypes of Iterable<VehicleStatus>.

In Java 8 you could perhaps add the new method without overriding and implement the old one as a default (or use abstract class in previous versions):

public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
    ...
    Iterable<V> getVehicleStatusesDec();

    default Iterable<VehicleStatus> getVehicleStatuses() {
        return (Iterable<VehicleStatus>) getVehicleStatusesDec();
    }
}

This should be safe because Iterable<T> doesn't have any methods which take T as argument: it "should" be covariant except Java doesn't support that; doing the same with e.g. List is a bad idea!

like image 51
Alexey Romanov Avatar answered Apr 17 '26 02:04

Alexey Romanov