Reputation: 6059
Let's assume, there is a method that returns an Object
, but we know it is some sort of typed List
(e.g. LinkedList<Long>
or ArrayList<String>
):
public abstract Object open();
Directly using its return value
List<Long> result = (List<Long>)dialog.open();
will cause a warning such as:
Type safety: Unchecked cast from Object to List
To overcome this problem, we can cast to List<?>
and then check each list item individually:
List<?> result = (List<?>)dialog.open();
List<Long> safeResult = new LinkedList<Long>();
for (Object obj: result) {
if (obj instanceof Long) {
safeResult.add((Long)obj);
}
}
Now I thought, wouldn't it be nice to have a generic method that can cast an Object
(that is known to contain a List
) to any typed instance of List
.
This is the closest I could get:
private <T> List<T> doSafeCast(Object listObject, Class<T> type) {
List<T> result = new LinkedList<T>();
if (listObject instanceof List) {
List<?> list = (List<?>)listObject;
for (Object obj: list) {
if (type.isInstance(obj)) {
result.add(type.cast(obj));
}
}
}
return result;
}
Now I can use it like this:
List<Long> safeResult = this.doSafeCast(dialog.open(), Long.class);
However, now I am bound to have LinkedList
s as result only.
Is it possible to specify the list type by passing an additional parameter, too?
I would want to to something like this:
List<Long> safeResult = this.doSafeCast(dialog.open(), Long.class, ArrayList.class);
List<String> anotherSafeResult = this.doSafeCast(anotherDialog.open(), String.class, LinkedList.class);
I know that all this seems overly complicated and I could just add @SuppressWarnings("unchecked")
to my initial unsafe cast, if I were sure that the dialog will always return the desired type. But I came up with this idea of having a general method to do such safe casts and now I want to know, if this is possible at all. So please don't suggest other solutions, I just want to learn about using generics a little more, here. :-) Thank you.
Upvotes: 1
Views: 2044
Reputation: 62864
Yes, you can. By simply introducing another type-parameter for the method and up-bound it to List
:
private <T, L extends List<T>> List<T> doSafeCast(Object listObject,
Class<T> type,
Class<L> listClass) {
List<T> result = listClass.newInstance();
if (listObject instanceof List) {
List<?> list = (List<?>) listObject;
for (Object obj : list) {
if (type.isInstance(obj)) {
result.add(type.cast(obj));
}
}
}
return result;
}
Note that you have to handle few possible exceptions.
Upvotes: 1