Let's start with the core bits of your API. You have a generic Parameter<T> type that represents some named parameter with a value of type T You have specialized GUI components designed to edit or display certain types of parameters, and you want to be able to register factories to create these components.
class Parameter<T> { String name; T defaultValue; } class ParameterComponent<P extends Parameter> { void setParameter(final P p) {} } interface ParameterComponentFactory<P extends Parameter> { ParameterComponent<P> newComponent(); } class FloatParameter extends Parameter<Float> {} class FloatParameterComponent extends ParameterComponent<FloatParameter> {} class EnumParameter extends Parameter<Enum> {} class EnumParameterComponent extends ParameterComponent<EnumParameter> {}
If I understand you correctly, you have encountered difficulties in figuring out how to declare a method that statically establishes a connection between some Parameter and factory for GUI components specialized for this type. For example, you want to write this:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
The problem is with the general subtyping rules, and you can get around them using a type variable instead of an inline template. This should give you the type check you want, without the need for an unpleasant cast:
static <P extends Parameter> void addComponentFactory( final Class<P> parameterType, final ParameterComponentFactory<? extends P> factory) { ... }
Explanation [1]
Explain the difference between introducing the new type P extends Parameter<?> Used in Class<P> and specifying Class<? extends Parameter<?>> Directly Class<? extends Parameter<?>>
It's complicated, so carry me. Let's talk a bit about wildcards, raw types, and conversions. Consider the following:
Scenarios 1 (a) and 1 (b) both compile for the same reason: since the raw type G can undergo an unchecked conversion to any parameterized form type G<T_1, ..., T_n> .
Scenario 2 does NOT . But why?
In Scenario 2, neither side of the second assignment is a raw type. For an assignment to be valid , there must be either an identity conversion or an extension of the conversion from the right type to the left type. To extend conversions to reference types, the left type must be a supertype of the right type. When these types are common, the general subtyping rules give expression. In particular, type arguments on the left should contain type arguments on the right.
A valid assignment from Class<String> to Class<? extends Object> Class<? extends Object> . Class<String> is a common subtype of Class<? extends Object> Class<? extends Object> because ? extends Object ? extends Object contains a String . In Scenario 2, the second assignment must be valid, the GenericParameter<?> Must contain the GenericParameter , but it is not. T not a subtype of T<?> ; T is a supertype of T<?> . Thus, according to the general rules of subtyping, Class<T> not a subtype of Class<T<?>> , and the assignment is not valid.
So why does the following work?
public static <P extends GenericParameter<?>> addParameterComponentFactory( Class<P> clazz, ParameterComponentFactory pcf) addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})
In the above call, the output type on P completely controlled by Class<P> . You pass a Class<EnumParameter> , so P in this case is bound to the raw type EnumParameter . To limit P extends GenericParameter<?> , GenericParameter<?> Must be assigned from EnumParameter , and it can be assigned through an uncontrolled conversion, as in scenarios 1 (a) and 1 (b).
[1] This blatant plug-in explanation combines the other excellent stack overflow responses, mostly radiodef .