I have the following classes:
class Field<T> {
private final Class<T> type;
public Field(Class<T> type) {
this.type = type;
}
}
class Pick<V> {
private final V value;
private final Class<V> type;
public Pick(V value, Class<V> type) {
this.value = value;
this.type = type;
}
}
and the class the question is related to:
class PickField<T> extends Field<Pick<T>> {
public PickField(Class<Pick<T>> type) {
super(type);
}
}
Now this seems to be accepted by the compiler. Unfortunately I do not know/understand how I could create a new instance of PickField
, e.g. for String
picks.
This does - of course - not work:new PickField<String>(Pick.class)
This is not allowed (I think I understand why):new PickField<String>(Pick<String>.class)
So how to do it? Or does the whole approach somehow "smell"?
I think PickField
should be parameterized with Pick
instances only.
So doing this should be fine:
class PickField<T extends Pick<T>> extends Field<T> {
public PickField(Class<T> c) {
super(c);
}
}
Then, you could just instantiate it with:
PickField<SomeSpecificPick> instance = new PickField<>(SomeSpecificPick.class);
where SomeSpecificPick
is defined as:
public class SomeSpecificPick extends Pick<SomeSpecificPick> {
public SomeSpecificPick(SomeSpecificPick value, Class<SomeSpecificPick> type) {
super(value, type);
}
}
More info (related with the topic):
There are various issues here.
Firstly as you point out, you cannot obtain the class of a parametrized type at compile time, since only one class is compiled for generic types, not one per given type parameter (e.g. the Pick<String>.class
idiom does not compile, and doesn't actually make sense).
Again as you mention, parametrizing the PickField<String>
constructor with Pick.class
only will not compile again, as the signatures aren't matched.
You could use a runtime idiom to infer the right Pick<T>
parameter, but that creates another problem: due to to type erasure, your type argument for T
will be unknown at runtime.
As such, you can parametrize your constructor invocation by explicitly casting, as follows:
new PickField<String>(
(Class<Pick<String>>)new Pick<String>("", String.class).getClass()
);
... which will compile with an "unchecked cast" warning (Type safety: Unchecked cast from Class<capture#1-of ? extends Pick> to Class<Pick<String>>
).
The real question is likely why do you need to know the value of type
in your Pick
class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With