General method call

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"); } } 

Compilation "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" with 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 skipped adding a 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 explain why compilation does not crash in the second case? I expected the compiler to complain about T extends Comparable, does V extend T in the second instance?

What's happening?

+7
java generics
source share
3 answers

The reason is related to PECS rules.

When you do it

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

You basically state that T and V are subtypes of Comparable . This means that calling arraysEqual(Integer[], Double[]) should work, because Integer and Double implement Comparable .

But when you add a 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 does not implement Comparable<Integer> , therefore a compiler error.

EDIT: If your question is why rawtype Comparable does not give a compiler error, the answer is how generics work ...

You can also try with Number ,

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

Rawtypes are not involved in this , and you can call arrayEquals(Integer[], Double[]) for this, and it will work fine, because both of them are Number .

+2
source share

The arraysEqual method has been arraysEqual for obtaining a type V that has T as a supertype. In other words, V must implement or extend T This does not apply to java.lang.Double ( V ) and java.lang.Integer ( T ) and therefore represents a compilation error.

Edited to add If you remove the parameterization from Comparable (declare it as Comparable not Comparable<T> ), the compiler sees T as Comparable , not Comparable<Integer> , and then V treated as V extends Comparable , which is java.lang.Double there is.

0
source share

The fact that he is doing well with raw Comparable is actually related to improving type inference in Java 8.

If you try to compile it with Java 7 javac, you will get:

  if (arraysEqual (nums, dVals))
                ^
   required: T [], V []
   found: Integer [], Double []
   reason: inferred type does not conform to declared bound (s)
     inferred: Double
     bound (s): Integer
   where T, V are type-variables:
     T extends Comparable declared in method arraysEqual (T [], V [])
     V extends T declared in method arraysEqual (T [], V [])

However, Java 8 is trying to find the right set of types that successfully fulfills the constraints. Instead of insisting that arrays are of types Integer[] and Double[] , they display them as Comparable[] and Double[] . Double declared to implement Comparable<Double> , which means it implements raw Comparable .

This cannot work when the generic type is used correctly, and Integer implements Comparable<Integer> , not raw Comparable , and Double does not implement this.

This example in the book seems a bit tricky, since you are not actually using compareTo in the method. You would encounter the same problem if you completely removed the restriction on T :

 static <T, V extends T> boolean arraysEqual(T[] x, V[] y){...} 

This would not compile in Java 7 for Integer[] and Double[] , since Double does not extend Integer . But in Java 8, it compiles because it displays the Number & Comparable<?> Type for T and Double extends it. Number & Comparable<?> Is the result of Java 8, which tries to find the most strict general type, so you can assign T to a variable of type Number or Comparable<?> Without an explicit cast.

0
source share

All Articles