我有来自" Java的这段代码 - 初学者指南 - Schildt',第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");
}
}
编译失败并显示消息 -
"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"
,
这是预期的。
但是,当我错过将参数添加到Comparable时(如下面的代码所示),代码会编译并生成正确的结果。
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");
}
}
有人可以解释为什么编译在第二个实例中没有失败?我原本以为编译器会抱怨 T扩展Comparable,V扩展T 在第二个实例中?
发生了什么?
答案 0 :(得分:2)
原因是PECS的规则。
当你这样做时,
static <T extends Comparable, V extends T> boolean arraysEqual(T[] x, V[] y)
您基本上是在说明,T和V都是Comparable
的子类型。
这意味着调用arraysEqual(Integer[], Double[])
应该有效,因为Integer
和Double
都会实现Comparable
。
但是当你将通用类型添加到Comparable
时,合同就会丢失,
static <T extends Comparable<T>, V extends T> boolean arraysEqual(T[] x, V[] y)
在此,Double
未实现Comparable<Integer>
,这就是编译器错误的原因。
编辑:如果您的问题是原型Comparable
没有给出编译器错误的原因,答案就是泛型如何工作......
您也可以尝试Number
,
static <T extends Number, V extends T> boolean arraysEqual(T[] x, V[] y)
此处不涉及 rawtypes ,您可以致电此arrayEquals(Integer[], Double[])
,它会正常工作,因为它们都是Number
。
答案 1 :(得分:0)
声明方法arraysEqual
以重新接收以V
作为超类型的T
类型。换句话说,V
必须实现或扩展T
。这不是java.lang.Double
(V
)和java.lang.Integer
(T
)的情况,因此构成编译错误。
已编辑添加
如果您从Comparable
中删除参数化(将其声明为Comparable
而不是Comparable<T>
),编译器会将T
视为Comparable
,而不是Comparable<Integer>
,并且然后V
被视为V extends Comparable
,java.lang.Double
。
答案 2 :(得分:0)
使用原始Comparable
成功的事实实际上是由于Java 8中改进的类型推断。
如果您尝试使用Java 7 javac进行编译,则会得到:
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[])
但是,Java 8正在尝试找到一组成功满足约束条件的正确类型。它不是坚持数组是Integer[]
和Double[]
类型,而是将它们推断为Comparable[]
和Double[]
。声明Double
实现Comparable<Double>
,这意味着它实现了原始Comparable
。
当正确使用泛型类型时,这不起作用,因为Integer
实现Comparable<Integer>
,而不是原始Comparable
,而Double
没有实现。{/ p>
本书中的这个例子似乎有点人为,因为你实际上并没有在方法中使用compareTo
。如果您完全删除T
上的约束,则会遇到同样的问题:
static <T, V extends T> boolean arraysEqual(T[] x, V[] y){...}
这不会在Java 7中针对Integer[]
和Double[]
进行编译,因为Double
不会扩展Integer
。但是在Java 8中,它会编译,因为它会推断Number & Comparable<?>
的类型T
和Double
扩展它。 Number & Comparable<?>
是Java 8试图找到最严格的公共类型的结果,因此您可以在没有显式强制转换的情况下将T分配给Number
或Comparable<?>
类型的变量。