有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java通用方法。多个参数匹配

我不明白为什么这段代码工作时没有错误

static <T> int compare(T t1, T t2) {
    return 0;
}

public static void main(String[] args) {
    compare(new Thread(), new StringBuilder());
}

因为当我们有这样的事情:

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    return;
}

public static void main(String[] args) {
    fromArrayToCollection(new Thread[] {}, new ArrayList<StringBuilder>()); // error
}

我们有个错误。 为什么编译器不检查第一个例子中两个参数的匹配?抱歉问了个愚蠢的问题


共 (2) 个答案

  1. # 1 楼答案

    泛型是不变的

    泛型是不变的,而不是协变的

    这意味着,虽然你可以这样做:

    Dog dog = new Dog();
    Animal animal = dog; // Dog works for Animal, classes are covariant
    

    你不能这样做:

    List<Dog> dogs = List.of(new Dog());
    List<Animal> animals = dogs; // Error, generics are invariant
    

    所以List<Dog>不是List<Animal>类型的。但是Dog属于Animal

    当然,这是有道理的,因为animals会接受Cat,但dogs不会


    解释

    在第一个代码中,您没有指定要使用的类型,例如:

    compare<Foo>(...)
    

    所以你让编译器推断类型。它搜索ThreadStringBuilder有共同点的类型,即Object

    所以T决定Object在那里,这很好:

    static int compare(Object t1, Object t2) {
        return 0;
    }
    

    在第二个示例中,它不能选择Object,因为Collection<Object>的行为与Collection<StringBuilder>不同,因为泛型是不变的。因此,它无法找到匹配的类型,因此会发生错误

    另见Why are arrays covariant but generics are invariant?

  2. # 2 楼答案

    我想补充一点,在第二个代码段中做一个简单的更改可以纠正错误:

    static <T> void fromArrayToCollection(T[] a, Collection<? extends T> c) { ... }
                                                                 ^
    

    现在,Java编译器将再次推断Object

    fromArrayToCollection(new Thread[]{}, new ArrayList<StringBuilder>());
    

    此外,还可以显式添加类型参数:

    Main.<Object>fromArrayToCollection(new Thread[]{}, new ArrayList<StringBuilder>());
            ^
    

    T => Object

    static void fromArrayToCollection(Object[] a, Collection<? extends Object> c) { ... }
    

    进一步阅读:Upper Bounded Wildcards