Home > Mobile >  Java Error: no instance(s) of type variable(s) C, T exist so that ? extends SubComponent<T> ca
Java Error: no instance(s) of type variable(s) C, T exist so that ? extends SubComponent<T> ca

Time:11-01

I have this quite complex class structure:

public interface SubComponent<T> {...}

public interface Component<T, C extends SubComponent<T>> {...}

public class Control<T, I extends Component<T, ? extends SubComponent<T>>> {...}

Then I have two classes that will hold the current state of the Control and of each Component, like this:

public class ControlState<T, I extends Component<T, ? extends SubComponent<T>>> {
    // The state keeps a reference to the Control,
    // and a map that holds all the states for each component
    private final Control<T, I> control;
    private final Map<Integer, ComponentState<T, ? extends SubComponent<T>>> components = new TreeMap<>();

    // Has a method to add new components
    public void addComponent(int index) {
        // Here I have error on the control parameter
        ComponentState<T, ? extends SubComponent<T>> state = new ComponentState<>(control, index);
        ...
    }
}

public class ComponentState<T, C extends SubComponent<T>> {
    // The component state also has a reference to the Control
    // and the index to retrieve the Component from a List in the Control
    private final Control<T, ? extends Component<T, C>> control;
    private final int index;

    public ComponentState(Control<T, ? extends Component<T, C>> control, int index) {
        this.control = control;
        this.index = index;
    }
}

In the addComponent(int index) method the IDE says:
Required type: Control<T, ? extends Component<T, C>>
Provided: Control<T, I>
But, since I is: I extends Component<T, ? extends SubComponent<T>> I don't understand where the issue is, types should be compatible, what am I doing wrong?

CodePudding user response:

As a workaround, I decided to simplify the model by removing the I information from the Control class.

As a result, the structure looks like this:

public interface SubComponent<T> {...}

public interface Component<T, C extends SubComponent<T>> {...}

public class Control<T> {
    private final List<? extends Component<T, ? extends SubComponent<T>>> components;
}

public class ControlState<T> {
    private final Control<T> control;
    private final Map<Integer, ComponentState<T>> components = new TreeMap<>();

    public void addComponent(int index) {
        ComponentState<T> state = new ComponentState<>(control, index);
        ...
    }
}

public class ComponentState<T> {
    private final Control<T> control;
    private Component<T, ? extends SubComponent<T>> component;
    private int index;
    private final Map<Integer, ? extends SubComponent<T>> subComponents = new TreeMap<>();

    public ComponentState(Control<T> control, int index) {
        this.control = control;
        this.index = index;
    }
}

That said, I would have preferred to keep that information, but I think I'm in a lucky position, meaning that as long as I tell the user that the components I need must be implementations of these two interfaces, internally I have all the APIs I need (exposed by the interfaces) to make the system work as intended

CodePudding user response:

I believe this should resolve your objective either properly or improperly. Thus, here is my idea.

In the addComponent() method of the ControlState class, you are trying to instantiate the ComponentState class. Now, while doing so, you can omit the Type Argument. Here, the memory allocation will happen like an object of the ComponentState class without a type argument, i.e. non-generic type, however, the actual object will still be referred to as generic typed.

Moreover, your control object was also not instantiated (either to null or properly)

public class ControlState<T, I extends Component<T, ? extends SubComponent<T>>> {
    // The state keeps a reference to the Control,
    // and a map that holds all the states for each component
    private final Control<T, I> control = null;
    private final Map<Integer, ComponentState<T, ? extends SubComponent<T>>> components = new TreeMap<Integer, ComponentState<T, ? extends SubComponent<T>>>();

    // Has a method to add new components
    public void addComponent(int index) {
        // Here I have error on the control parameter
        ComponentState<T, ? extends SubComponent<T>> state = new ComponentState(control, index);
    }
}
  • Related