Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Method invocation

Tags:

java

generics

I have this piece of code from "Java - A beginner's Guide - Schildt', Chapter 13:

package com.chapter.thirteen;

public class GenericMethodDemo {
static <T extends Comparable<T>, V extends T> boolean arraysEqual(T[] x, V[] y){
    if(x.length != y.length) return false;

    for(int i = 0; i < x.length; i++)
        if(!x[i].equals(y[i])) return false;

    return true;
}

public static void main(String args[]){

    Integer [] nums  = { 1, 3, 3, 4, 6 };
    Integer [] nums2 = { 1, 3, 3, 4, 6 };
    Integer [] nums3 = { 1, 3, 3, 4, 6 };
    Integer [] nums4 = { 1, 3, 3, 4, 6, 7};
    Double [] dVals = {1.1, 2.2, 3.3, 4.4};

    if(arraysEqual(nums, nums))
        System.out.println("nums equal nums");

    if(arraysEqual(nums, nums2))
        System.out.println("nums equal nums2");

    if(arraysEqual(nums, nums2))
        System.out.println("nums equal nums2");

    if(arraysEqual(nums, nums3))
        System.out.println("nums equal nums3");

    if(arraysEqual(nums, nums4))
        System.out.println("nums equal nums4");

    //Edit:Removed the comments from the below two lines.

    if(arraysEqual(nums, dVals))
        System.out.println("Nums equal dVals");

    }
}

The compilation fails with the message - "Error:(39, 12) java: method arraysEqual in class com.chapter.thirteen.GenericMethodDemo cannot be applied to given types; required: T[],V[] found: java.lang.Integer[],java.lang.Double[] reason: inference variable T has incompatible bounds equality constraints: java.lang.Integer lower bounds: V,java.lang.Double,java.lang.Integer", which is expected.

However, when I missed adding the parameter to Comparable (as shown in the code below), the code compiles and produces the correct result.

package com.chapter.thirteen;


public class GenericMethodDemo {
    static <T extends Comparable, V extends T> boolean arraysEqual(T[] x, V[] y){
    if(x.length != y.length) return false;

    for(int i = 0; i < x.length; i++)
        if(!x[i].equals(y[i])) return false;

    return true;
}

public static void main(String args[]){

    Integer [] nums  = { 1, 3, 3, 4, 6 };
    Integer [] nums2 = { 1, 3, 3, 4, 6 };
    Integer [] nums3 = { 1, 3, 3, 4, 6 };
    Integer [] nums4 = { 1, 3, 3, 4, 6, 7};
    Double [] dVals = {1.1, 2.2, 3.3, 4.4};

    if(arraysEqual(nums, nums))
        System.out.println("nums equal nums");

    if(arraysEqual(nums, nums2))
        System.out.println("nums equal nums2");

    if(arraysEqual(nums, nums2))
        System.out.println("nums equal nums2");

    if(arraysEqual(nums, nums3))
        System.out.println("nums equal nums3");

    if(arraysEqual(nums, nums4))
        System.out.println("nums equal nums4");

    if(arraysEqual(nums, dVals))
        System.out.println("Nums equal dVals");
   }
}

Can someone please explain why the compilation does not fail in the second instance? I had expected the compiler to complain about T extends Comparable, V extends T in the second instance?

What's going on?

like image 987
theguyoverthere Avatar asked Oct 27 '15 08:10

theguyoverthere


People also ask

How do you invoke a generic method?

To call a generic method, you need to provide types that will be used during the method invocation. Those types can be passed as an instance of NType objects initialized with particular . NET types.

What are the generic methods?

Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.

Can you give an example of a generic method?

For example, classes like HashSet, ArrayList, HashMap, etc., use generics very well. There are some fundamental differences between the two approaches to generic types.

Can you directly invoke generic method using .NET reflection?

Luckily, this is quite easy to do with the help of reflection. The first step to dynamically invoking a generic method with reflection is to use reflection to get access to the MethodInfo of the generic method. To do that simply do this: var methodInfo = typeof(ClassWithGenericMethod).


1 Answers

The reason is because of the rules of PECS.

When you do,

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

You are basically stating, both T and V are subtype of Comparable. Which means calling arraysEqual(Integer[], Double[]) should work because both Integer and Double implement Comparable.

But when you add generic type to Comparable, the contract is lost,

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

In this, Double is not implementing Comparable<Integer>, which is why the compiler error.

EDIT: If your question is why the rawtype Comparable is not giving compiler error, the answer is that's how generics work...

You can try with Number too,

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

No rawtypes are involved in this, and you can call arrayEquals(Integer[], Double[]) to this and it will work fine because both are Number.

like image 181
Codebender Avatar answered Sep 19 '22 21:09

Codebender