I was able to find how to declare generics with single argument and multiple constrains and generics with multiple arguments, but strangely enough, not a generic with multiple argument and constraints:
public class Page<U, T implements IPaginableBy<U>> extends ArrayList<T> { }
gives me syntax error after T: "java: > expected". Is it not possible to constrain a an argument on generic type more than one argument?
Change
public class Page<U, T implements IPaginableBy<U>> extends ArrayList<T> { }
to
public class Page<U, T extends IPaginableBy<U>> extends ArrayList<T> { }
Constrained type arguments always use the extends keyword.
Related
I'm using library which contains method I want to use. Simplified signature would look like this:
final class ThirdPartyClass
{
public static <T> void thirdPartyMethod(Class<T> clazz, T instance)
{
// does something
}
}
Inside thirdPartyMethod() it expects class of T as first argument and an instance of that specific class T as second argument.
Now I have this simple abstract class, which is calling that method:
abstract class Parent<T extends Number>
{
public Parent(T instance)
{
ThirdPartyClass.thirdPartyMethod(instance.getClass(), instance);
}
}
I'm getting an error:
method thirdPartyMethod in class ThirdPartyClass cannot be applied to given types;
required: java.lang.Class, T
found: java.lang.Class<capture#1 of ? extends java.lang.Number>, T
reason: inference variable T has incompatible bounds
equality constraints: capture#2 of ? extends java.lang.Number
lower bounds: T
How can I modify the Parent class so it conforms to expected arguments of thirdPartyMethod()?
If possible with explanation.
According to the return type of Object.getClass()
The actual result type is Class<? extends |X|> where |X| is the
erasure of the static type of the expression on which getClass is
called.
Since T extends Number, the resulting type would be Class<? extends Number>, i.e. means an unknown type extending Number. Which doesn't match T extends Number (i.e. a particular type extending Number which would be provided at runtime).
How can I modify the Parent class so it conforms to expected arguments of thirdPartyMethod()?
1. Introduce a second parameter of type Class<T> in your constructor.
abstract class Parent<T extends Number> {
public Parent(T instance, Class<T> tClass) {
ThirdPartyClass.thirdPartyMethod(tClass, instance);
}
}
2. Perform casting (as have been mentioned in the comments):
ThirdPartyClass.thirdPartyMethod((Class<T>) instance.getClass(), instance);
By the way, instead of calling methods from a constructor (especially ones that are not developed and tested by you/your colleagues) you might consider introducing a factory method that would produce your domain object based on the result of a method call.
This is an oversimplified version of the compiler behaviour I'm trying to understand:
class Scratch {
public static void main(String[] args) {
HouseCat<? extends Mammal> hcat = new Tabby();
//HouseCat<Mammal> won't work, compiler catches incorrect type parameter bound
HouseCat<CrazyHouseCat> crazyCat = new Tabby();
}
}
interface Mammal<T extends Mammal> extends Comparable<T>{
T cloneInstance();
}
interface Feline<T extends Feline> extends Mammal<T>{}
interface HouseCat <T extends HouseCat> extends Feline<T>{}
interface CrazyHouseCat<T extends CrazyHouseCat> extends HouseCat<T>{
void pushStuffOverTvStand();
}
class Tabby implements CrazyHouseCat<CrazyHouseCat>{
#Override
public CrazyHouseCat cloneInstance() {
return null;
}
#Override
public void pushStuffOverTvStand() {
}
#Override
public int compareTo(CrazyHouseCat o) {
return 0;
}
}
In the snippet above, HouseCat<? extends Mammal> is a reference with a wider range of types than that is allowed by the HouseCat interface, namely: HouseCat<T extends HouseCat>
If I were to try to do something like HouseCat<Long> the compiler would tell me that Long does not satisfy the type parameter's constraints. Well, so does not <? extends Mammal>, at least potentially.
The compiler would not let me create an instance that violates the type parameter T's constraints but I'm confused about its behaviour regarding the use of Mammal as the upper bound of the reference. There is an invalid type range between (HouseCat,Mammal] so why won't the compiler refuse this reference definition?
Clarification:
My question is not about the meaning of wildcard ?. I'm asking why the compiler is allowing a reference to a parameterised type instance be defined using a wider range of types than what is allowed by the parameterised type's definition. The mentioned questions do not address this specific case, they're about the meaning of a wildcard. My question is about the valid range of the wildcard, which the compiler does not seem be enforcing.
This looks like it answers your question. Basically HouseCat<? extends Mammal> allows to create a HouseCat<[insert type that extends Mammal here]>. All <? extends Mammal> does is act as a generic. In your example I don't see why you'd try to do it this way, but I hope this helps.
I use Java 8. In my design a have a few simple classes which model value parameters such as FloatParameter or EnumParameter<E>. A have a common generic super class of these classes (GenericParameter<T>) which implements parameter name and its default value. The sub classes implement other attributes specific to them such as range in case of FloatParameter.
Moreover, I want to work with the types of the parameters regardless of their specific type. But I still want to bound the types in the way that they are sub types of GenericParameter<T>. In order to do that, I created a method such as process(Class<? extends GenericParameter<?>> paramType).
Now, the problem is that the EnumParameter.class cannot be assigned to a variable of type Class<? extends GenericParameter<?>> while FloatParameter.class can be.
Further I list the code for the classes to make it more clear and reproducible:
public class GenericParameter<T> {
protected String name;
protected T defaultValue;
}
public class FloatGenericParameter extends GenericParameter<Float> {
...
}
public class TypedGenericParameter<T> extends GenericParameter<T> {
...
}
Class<? extends GenericParameter<?>> fgpc = FloatGenericParameter.class; // ok
Class<? extends GenericParameter<?>> tgpc = TypedGenericParameter.class; // error: incompatible types: Class<TypedGenericParameter> cannot be converted to Class<? extends GenericParameter<?>>
Class<? extends GenericParameter> tgpc2 = TypedGenericParameter.class; // warning: [rawtypes] found raw type: GenericParameter
Finally, when using a non-generic base class, there is no problem:
public class Parameter {
....
}
public class FloatParameter extends Parameter {
...
}
public class TypedParameter<T> extends Parameter {
...
}
Class<? extends Parameter> fpc = FloatParameter.class; // ok
Class<? extends Parameter> tpc = TypedParameter.class; // ok
Please, do you have any suggestions?
I can go with process(Class<?> paramType) as a workaround or do casts, but I wanted to benefit from the static type checking by the compiler.
EDIT:
I would like to use the cast when registering factories that produce GUI components for each parameter type. The code looks like:
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })
In such case, the compiler would check the added parameter type at compile time. Also the code would be more self-explaining.
EDIT 2:
Currently, I am using the suggested approach to introduce a type parameter for the addParameterComponentFactory method. The signature looks like this:
public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)
With this definition I am able to specify TypedParameter.class (EnumParameter.class - also one type param) as well as I obtain the static type checking.
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 specific 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're running into trouble figuring out how to
declare a method that statically enforces a relationship between some
Parameter type and a factory for GUI components specialized for that type.
For example, you want to be able to write this:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
The problem is related to the rules of generic subtyping, and you can work around them by employing a type variable instead of an embedded wildcard. This should give you the type checking you want, without the need for
nasty casting:
static <P extends Parameter> void addComponentFactory(
final Class<P> parameterType,
final ParameterComponentFactory<? extends P> factory) { ... }
Explanation[1]
Explain the difference between introducing a new type P extends Parameter<?> used in Class<P> and stating
directly Class<? extends Parameter<?>>
This is complicated, so bear with me. Let's talk a bit about wildcards, raw
types, and conversions. Consider the following:
// Scenario 1(a)
GenericParameter raw = /* some value */;
GenericParameter<?> wc = raw;
// Scenario 1(b)
Class raw = GenericParameter.class;
Class<?> wc = raw;
// Scenario 2
Class<GenericParameter> classOfRaw = GenericParameter.class;
Class<GenericParameter<?>> classOfWC = classOfRaw;
Scenarios 1(a) and 1(b) both compile for the same reason: because a raw type
G may undergo an unchecked conversion
to any parameterized type of the form G<T_1, ..., T_n>.
Scenario 2 does NOT compile. But why?
In Scenario 2, neither side in the second assignment is a raw type. For the
assignment to be valid,
there must be either an identity conversion or a widening conversion
from the right-hand type to the left-hand type. For widening conversions on
reference types, the left-hand type must be a supertype of the right-hand type.
When these types are generic, the rules of generic subtyping
apply. Specifically, the type arguments on the left-hand side must
contain
the type arguments on the right-hand side.
An assignment from Class<String> to Class<? extends Object> is valid.
Class<String> is a generic subtype of Class<? extends Object> because
? extends Object contains String. In Scenario 2, for the second
assignment to be valid, GenericParameter<?> would have to contain
GenericParameter, but it doesn't. T is not a subtype of T<?>;
T is a supertype of T<?>. Thus, by the generic subtyping rules,
Class<T> is 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 call above, type inference on P is driven entirely by the
Class<P> argument. You are passing a Class<EnumParameter>, so P
in this case gets bound to the raw type EnumParameter. For the constraint
P extends GenericParameter<?> to be satisfied, GenericParameter<?>
must be assignable from EnumParameter, and it is assignable via an
unchecked conversion, just like in Scenarios 1(a) and 1(b).
[1] This explanation is blatant plagarism
an amalgamation of other excellent Stack Overflow answers, mostly by
radiodef.
Is it possible to use wildcards as an attribute itself and not as a type parameter?
public void doSomething(<? extends Context> myObject){
}
I want to make sure that my object extends Context and also implements a certain interface.
Using wildcards as a return type is valid but using it as an attribute seems to not work
public <? extends MyClass> validMethod(){
}
Yes it's possible, you have to define it before the return type.
public <T extends MyClass> void myMethod(T param);
You don't explicitly state (for your case) which is the interface and which is the class, but if you wanted to have a generic type bound to both extending a class and an interface, this would be the general form for it.
public <T extends Number & Comparable<T>> T findNumber(List<T> elements) { }
Number is an abstract class; Comparable is an interface. I believe what you have to specify them in this order - concrete before interface.
I am unable to get this to compile and I don't see the reason why.
Ultimately I want to pass an Collection of objects who's class extends TClass into the generate method that takes a Collection of objects who's class extends TClass,
This should work.
Any help would be appreciated.
public interface Generator<IT extends ITClass, T extends TClass> {
IT generate(Collection<T> tClassCollection)
}
Generator<?, ? extends TClass> generator = generatorClass.newInstance();
Collection<? extends TClass> TClassCollection = ...
... generator.generate(TClassCollection);
I get this error
The method generate(Collection<capture#8-of ? extends TClass>) in the type
Generator<capture#7-of ?,capture#8-of ? extends TClass> is not applicable for the arguments (Collection<capture#9-of ? extends TClass>)
This should work
No; it would open a loophole in the type system if it did. Consider:
class SpecialT extends TClass {}
class SpecialGenerator extends Generator<ITClass, SpecialT> {}
Generator<?, ? extends TClass> generator = SpecialGenerator.class.newInstance();
Collection<? extends TClass> TClassCollection = Arrays.asList(new TClass());
generator.generate(TClassCollection);
A SpecialGenerator can only work with a Collection<SpecialT>, but you are trying to pass a Collection<TClass>, which can contain instances of types other than SpecialT.
A wildcard in a generic declaration doesn't mean "any type"; it means "some particular unknown type."
So, if you have a Generator<?, ? extends TClass>, it doesn't mean you can pass its generate() method any Collection as long as it contains a subtype of TClass.
On the contrary, it means that you can't invoke its generate() method in a type-safe way, because you don't know the type of elements it is capable of accepting.