I want to have a method that generically creates a list of a specified interface. I can't seem to get it so that I don't have to cast or that I loose my type-safety.
This version requires casting of the Set and produces unsafe type cast warnings:
public static Set<? extends Setting> getSettings(Class<? extends Setting> className){
Set<? extends Setting> result = new HashSet<>();
try {
Setting settingsObject = className.getDeclaredConstructor().newInstance();
// do something with it and populate result-set
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
Set<LiabilitySetting> liabilitySettings = (Set<LiabilitySetting>) getSettings(LiabilitySetting.class);
for (LiabilitySetting s: liabilitySettings) {
s.doSomething();
}
}
while with this version I need to cast the elements of the set before using them
public static Set<Setting> getSettings(Class<? extends Setting> className){
Set<Setting> result = new HashSet<>();
try {
Setting settingsObject = className.getDeclaredConstructor().newInstance();
// do something with it and populate result-set
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
Set<Setting> liabilitySettings = getSettings(LiabilitySetting.class);
for (Setting s: liabilitySettings) {
((LiabilitySetting) s).doSomething();;
}
}
I feel there is a way of writing my method without loosing type-safe and without having to cast. Any ideas?
Use a bounded type parameter instead.
public static <T extends Setting> Set<T> getSettings(Class<T> className) {
The wildcard ?
tells the compiler that it's some subclass of Setting
(or Setting
itself), but the compiler doesn't know whether the ?
in the Class
is the same as the ?
in the Set
.
When you bind it to a type parameter, the compiler still knows that T
is a subclass of Setting
or Setting
, but now it knows that the Set
and the Class
have the same type, removing the need for a cast.