简体   繁体   中英

Java Generics: Static method of a specific argument Type does not match the Functional Interface

The first assignment below doesn't compile, but I am not sure why, the method signature of the static method matches the functional method signature albeit it is not using type arguments. The second line compiles fine even though it is the same signature except for the type parameterization.

What is the reasoning behind this?

public class GenericSample<T> {
    public static void staticLambdaMtd(Integer a) {
            
    }   

    public static<X> void staticLambdaMtd2(X a) {
            
    }  

    // Funca<T> fa1 = GenericSample::staticLambdaMtd;//does not compile !

    Funca<T> fa = GenericSample::staticLambdaMtd2;//does compile !      
}
    
interface Funca<A> {
    public void funct(A a);
}

You are mixing a generic parameter T and a type Integer . That wouldn't work because T and Integer are different types.

Generics are invariant . That means you can assign to a List<Person> only another list having the same generic parameter, ie Person (not Integer , Cat or T ). Similarly, we can't assign Funca<Integer> to a variable of type Funca<T> .

For more information, have a look at this tutorial provided by Oracle.

A function created using a static method staticLambdaMtd(Integer a) is assignable only to a variable of type Funca<Integer> , but not Funca<T> - ie function of some arbitrary type, because only Integer type would match the method signature, but not any type (like String , Cat , BigDecimal ) that would be defined while class GenericSample will get instantiated.

The second statement compiles fine, because it doesn't expect any specific type. X is only a placeholder, as well as T . And expression GenericSample::staticLambdaMtd2 should be classified as a so-called poly expression , ie because you're not providing a type compiler needs to infer it from the assignment context.

Therefore, the expression GenericSample::staticLambdaMtd2 would be inferred as being of type Funca<T> and the second statement will compile fine.

All assignments shown below are valid:

// expression on the right could represent only `Funca<Integer>`

Funca<Integer> fa1 = GenericSample::staticLambdaMtd;


// expression on the right can be succefully inferred to 
// a function of any type based on the assingment context on the left

Funca<T> fa = GenericSample::staticLambdaMtd2;      
Funca<String> fa = GenericSample::staticLambdaMtd2;
Funca<BigDecimal> fa = GenericSample::staticLambdaMtd2;

Note that expression GenericSample::staticLambdaMtd2 can be turned from a poly expression into a "standalone form" by providing a generic parameter ( in fact, method references by definition provided in the specification are always poly expressions , therefore I've used "standalone" in quotation marks meaning only that assignment context will be ignored ).

And that we how can break it:

// that will not compile for the same reason as the the firt statement doesn't compile

Funca<T> fa3 = GenericSample::<Integer>staticLambdaMtd2;

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