简体   繁体   中英

Generic method to cast from Object to typed instance of List

Let's assume, there is a method that returns an Object , but we know it is some sort of typed List (eg 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM