通用方法调用

时间:2015-10-27 08:23:27

标签: java generics

我有来自" 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 在第二个实例中?

发生了什么?

3 个答案:

答案 0 :(得分:2)

原因是PECS的规则。

当你这样做时,

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

您基本上是在说明,T和V都是Comparable的子类型。 这意味着调用arraysEqual(Integer[], Double[])应该有效,因为IntegerDouble都会实现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.DoubleV)和java.lang.IntegerT)的情况,因此构成编译错误。

已编辑添加 如果您从Comparable中删除参数化(将其声明为Comparable而不是Comparable<T>),编译器会将T视为Comparable,而不是Comparable<Integer>,并且然后V被视为V extends Comparablejava.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<?>的类型TDouble扩展它。 Number & Comparable<?>是Java 8试图找到最严格的公共类型的结果,因此您可以在没有显式强制转换的情况下将T分配给NumberComparable<?>类型的变量。