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?
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.
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.
For example, classes like HashSet, ArrayList, HashMap, etc., use generics very well. There are some fundamental differences between the two approaches to generic types.
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).
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With