开发者

When is a parameterized method call useful?

开发者 https://www.devze.com 2022-12-29 22:40 出处:网络
A Java method call may be parameterized like in the following code: class Test { <T> void test() { }

A Java method call may be parameterized like in the following code:

class Test
{
    <T> void test()
    {
    }

    public static void main(String[] args)
    {
        new Test().<Object>test();
        //         ^^^^^^^^
    }
}

I found out this is possible from the Eclipse Java Formatter settings dialog and wondered if there are any cases where this is useful or required.


EDIT

Based on Arne's excellent answer i came up with the following conclusion:

In addition to improved type safety as Arne's example illustrates a parameterized method call enabl开发者_JS百科es you to specify the common base type of the methods arguments that should be the type of the container elements. This type is normally inferenced automatically by the compiler to the most specific common base type. By parameterizing the method call this behaviour may be overridden. A parameterized method call may be required if there are multiple common types inferenced by the compiler.

The following example demonstrates that behaviour:

import java.util.Arrays;
import java.util.List;

class Test
{
    public static void main(String[] args)
    {
        Integer a=new Integer(0);
        Long    b=new Long(0);
        List<Object> listError=Arrays.asList(a, b);
        //error because Number&Comparable<?> is not Object
        List<Object> listObj=Arrays.<Object>asList(a, b);
        List<Number> listNum=Arrays.<Number>asList(a, b);
        List<Comparable<?>> listCmp=Arrays.<Comparable<?>>asList(a, b);
    }
}

This behaviour is defined in The Java Language Specification Third Edition paragraphs 8.4.4 and 15.12.2.7 but not easily understood.


I never have used this in practice, but you can imagine to use this for type safety. Consider the following method:

<T> void method(T... items) {
    List<T> list = new ArrayList<T>();
    for (T item : items)
        list.add(item);
    System.out.println(list);
}

You can call it this way:

o.<Object>method("Blah", new Long(0));
o.<Number>method(new Integer(100), new Long(0));

But this will raise an compiler error:

o.<Number>method("String", new Long(0));

So you have an generic method that is typesafe and can be used for every Object, not limited to a paricular interface or class.


Parameterized method calls are useful when you want to allow different types without casting. For example, the Collections helper class makes extensive use of parameterized method calls. When you want to make a new generic collection using one of their helper methods, a few examples:

List<String> anEmptyStringList = Collections.<String>emptyList();
Set<Integer> unmodifiableCopy = Collections.<Integer>unmodifiableSet(originalSet);

So, when you want to be able to use the generic type elsewhere, you want to use those method calls. They prevent compiler warnings when using generics.


It is probably most useful when you are taking a collection of some type, and returning some subset of that collection.

<T> List<T> filter(Collection<? extends T> coll, Predicate<? super T> pred) {
    List<T> returnList = new ArrayList<T>();
    for(T t : coll) {
        if(pred.matches(t)){
            returnList.add(t);
        }
    }
    return returnList;
}

Edit:

More generally, it is useful whenever you wish to return a specific type, or you want to link the types of two or more parameters in a general way.


For example, when you need some universal method for comparisons:

public static <T extends Comparable> T max(T one, T two) {
    if (one.compareTo(two) > 0) {
        return one;
    } else {
        return two;
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号