简体   繁体   中英

What's the difference between Java 8 and Java 7 related to generic methods in type parameter bound?

public class GenMethodDemo2 {
    static <T, V extends T> boolean isIn(T x, V[] y){
        for (int i = 0; i < y.length; i++) {
            if (x.equals(y[i])) return true;
        }
        return false;
    }

    @Test
    public void test(){
        Integer[] nums = {1,2,3,4,5};
        if(isIn("java",nums)) System.out.println("java is in nums");
        if(!isIn("java",nums)) System.out.println("java is not in nums");
    }
}

when i use jdk8 this code running well, and result is java is not in nums

but when i change to jdk7 the same code will not complie, and the prompt msg is Inferred type 'java.lang.Integer' for type parameter 'V' is not within its bound; should extend 'java.lang.String' Inferred type 'java.lang.Integer' for type parameter 'V' is not within its bound; should extend 'java.lang.String'

i want to know: how jdk8 can complie this code, when the funcation explicit define type parameter bound V extends T ?

I believe there are some improvements in type inference for generic methods in Java 8 compared to Java 7, though I am not sure it would explain the difference you are seeing. In any case, when inference fails, you can always explicitly provide a type witness to prove to the compiler that there exists a type where the bounds will be met, like:

if (GenMethodDemo2.<Object, Integer>isIn("java",nums))
    System.out.println("java is in nums");

In this case, both type variables T and V can always be chosen to be Object , and it won't accept any fewer set of parameters (since any T will be a subtype of Object and any V[] will be a subtype of Object[] ). So your method doesn't actually need any generics:

static boolean isIn(Object x, Object[] y){
    for (int i = 0; i < y.length; i++) {
        if (x.equals(y[i])) return true;
    }
    return false;
}

A signature like

static <T, V extends T> boolean isIn(T x, V[] y)

is not much better than

static boolean isIn(Object x, Object[] y)

as the caller can always use Object for T which allows an arbitrary object as first argument, as well as an arbitrary reference type for the array's elements.

Hence, when you change the method to

@Test
public void test(){
    Integer[] nums = {1,2,3,4,5};
    if(GenMethodDemo2.<Object,Integer>isIn("java",nums))
            System.out.println("java is in nums");
    if(!GenMethodDemo2.<Object,Integer>isIn("java",nums))
            System.out.println("java is not in nums");
}

it can be compiled in all Java versions which support Generics.

Due to the covariant arrays, it would also work to specify

if(GenMethodDemo2.<Object,Object>isIn("java",nums))
        System.out.println("java is in nums");
if(!GenMethodDemo2.<Object,Object>isIn("java",nums))
        System.out.println("java is not in nums");

Java 8's type inference does not change which method invocation is valid, it only makes it easier to perform the valid invocations, as you have less scenarios where you need to specify type arguments explicitly.

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