简体   繁体   中英

Java generics - purpose of wildcard except for lower bounds?

What is the purpose of using a wildcard for unbounded or upper-bounded generics? More specifically:

Why would I say public static void foo(List<?> bar) instead of public static <E> void foo(List<E> bar) ?

Why would I say public static void foo(List<? extends Baz> bar) instead of public static <E extends Baz> void foo(List<E> bar) ?

If you are not ever going to refer to E in the code that follows, there is no need to declare it.

Reduces programmer memory strain.

If the type of the list is decided at runtime, then you will need to use wildcards.

The following program will print a List<String> if run with any command-line arguments; otherwise it will print a List<Number> :

public class Test {

    public static List<String> listOfStrings = Arrays.asList("hello", "world");
    public static List<Number> listOfNumbers = Arrays.asList(1, 2, 3, 4.5);

    public static List<?> getListOfUnknown(boolean arg) {
        if(arg) return listOfStrings;
        else return listOfNumbers;
    }

    public static void main(String[] args) {
        System.out.println(getListOfUnknown(args.length > 0));
    }
}

The versions with a wildcard are preferred. If a parameter has type List<?> it is clear that any List will be accepted. If any List is accepted, there's no reason to give the type parameter a name, so writing <E> would just be clutter. On the other hand, if the type parameter appears twice in the signature, then you cannot use wildcards. For example, this signature needs a type parameter.

public static <E> List<E> combineLists(List<E> list1, List<E> list2)

Actually in that example it would probably be better if the arguments had type List<? extends E> List<? extends E> (the only way to do that without wildcards would be to have three type parameters, a total mess).

In Effective Java, it is recommended that even if the type parameter is needed in the body of the method, you should prefer the version of the signature with a wildcard, and write a private helper method to make this possible. For example:

public static void swapFirstAndLast(List<?> list) {
    helper(list);
}

private static <E> void helper(List<E> list) {
    int size = list.size();
    E e = list.get(0);
    list.set(0, list.get(size - 1)); // These lines would not be possible
    list.set(size - 1, e);           // If the type of list were List<?>
}

The official tutorial for generic method already explained well enough.

... the type parameter T is used only once. The return type doesn't depend on the type parameter, nor does any other argument to the method (in this case, there simply is only one argument). This tells us that the type argument is being used for polymorphism; its only effect is to allow a variety of actual argument types to be used at different invocation sites. If that is the case, one should use wildcards. ...

Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used.

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