3

在以下代码示例中:

interface Eatable{ public void printMe();}
class Animal { public void printMe(){System.out.println("Animal object");}}
class Dog extends Animal implements Eatable{ public void printMe(){System.out.println("Dog object");}}
class BullTerrier extends Dog{ public void printMe(){System.out.println("BullTerrier object");}}

public class ZiggyTest{

    public static void main(String[] args) throws Exception{

        Object[] objArray = new Object[]{new Object(), new Object()};
        Collection<Object> objCollection = new ArrayList<Object>();

        Animal[] animalArray = new Animal[]{new Animal(),new Animal(),new Animal()};
        Collection<Animal> animalCollection = new ArrayList<Animal>();      

        Dog[] dogArray = new Dog[]{new Dog(),new Dog(),new Dog()};
        Collection<Dog> dogCollection = new ArrayList<Dog>();

        System.out.println(forArrayToCollection(animalArray,animalCollection).size());
        // System.out.println(forArrayToCollection(dogArray,dogCollection).size());  #1 Not valid

        System.out.println(genericFromArrayToCollection(animalArray,animalCollection).size());
        System.out.println(genericFromArrayToCollection(dogArray,dogCollection).size());  


        System.out.println(genericFromArrayToCollection(animalArray,objCollection).size()); //#2 
        System.out.println(genericFromArrayToCollection(dogArray,animalCollection).size()); //#3 
        // System.out.println(genericFromArrayToCollection(objArray,animalCollection).size()); //#4

    }

    public static Collection<Animal> forArrayToCollection(Animal[] a, Collection<Animal> c){
        for (Animal o : a){
            c.add(o);
        }

        return c;
    }

    static <T> Collection<T> genericFromArrayToCollection(T[] a, Collection<T> c) {
        for (T o : a) {
            c.add(o); 
        }

        return c;
    }

}

为什么编译器genericFromArrayToCollection()只有在集合的声明类型是数组声明类型的父级时才允许调用该方法(参见标记为 #2、#3 和 #4 的行)。请问这是为什么?

谢谢

编辑

当我取消注释标记为 #4 的行时,出现以下错误

ZiggyTest.java:34: <T>genericFromArrayToCollection(T[],java.util.Collection<T>) in ZiggyTest cannot be applied to (java.lang.Object[],java.util.Collection<Animal>)
                System.out.println(genericFromArrayToCollection(objArray,animalCollection).size()); //#4
                                   ^
1 error

编辑 2

@Tudor 我使用此语句尝试了以下方法

System.out.println(method1(new ArrayList<String>()).size());

编译器报错说不能应用于 java.util.ArrayList

public static Collection<Object> method1(ArrayList<Object> c){
        c.add(new Object());
        c.add(new Object());        
        return c;
}
4

3 回答 3

1

因此,您作为方法参数提供的静态类型是有序的:

对于forArrayToCollection.

Animal[], Collection<Animal>
Dog[], Collection<Dog>

这个方法有参数类型Animal[], Collection<Animal>。第一次通话完全匹配。第二次调用尝试分配错误的 a (我可以将 a 添加Collection<Animal>到a ,但我不应该对 a 执行此操作)。Collection<Dog>CatCollection<Animal>Collection<Dog>

对于genericFromArrayToCollection.

Animal[], Collection<Animal>
Dog[], Collection<Dog>

Animal[], Collection<Object>
Dog[], Collection<Animal>
Object[], Collection<Animal>

在所有情况下,都T必须替换集合的通用参数。前两个调用完全匹配。对于第三个调用,TisObject和由于数组在 Java 中的奇怪行为方式,Animal[]可以分配给 an Object[](但ArrayStoreException如果您尝试将 a 存储NumberFormat在其中,您将得到一个未选中的值)。同样,对于第四个,Dog[]可以分配给Animal[]。对于最后一个Object[]不能分配给Animal[](从数组中读取永远不应该抛出 a ClassCastException,除非你用一个通用的数组强制转换怪物做了一些不合理的事情(你会得到一个 javac 警告 - 请注意它))。

于 2011-12-03T12:53:05.600 回答
1

为了回答你的问题,我们首先建立一个前提:我们知道如果你有一个方法以数组作为参数,你可以传递一个子类型的数组:

public void method(Object[] list) // can be called with String[]

但反之则不然:

public void method(String[] list) // cannot be called with Object[]

然后,归结为泛型方法的参数是如何实际实例化的,这就是参数类型推断的工作原理。在您的情况 #3 中,它被推断为 Animal,因此方法声明看起来像:

static Collection<Animal> genericFromArrayToCollection(Animal[] a, 
                                                       Collection<Animal> c) {

并且由于Dog是 的子类型Animal,因此它可以很好地代替Animal[]数组。与案例 #2 相同。

但是,在第 4 种情况下,类型再次被推断为 Animal,因此方法如上所示,但您不能将Object[]数组替换为Animal[]数组,因为Object它不是Animal.

于 2011-12-03T12:58:07.503 回答
1

基本上,genericFromArrayToCollection() 将 T 定义为类型参数,用于定义 2 个方法参数(即T[]a 和Collection<T>c)。a 和 c 都必须基于相同的类型,所以Dog[]andCollection<Dog>会工作,Animal[]并且Collection<Animal>会工作,但不会Object[]Collection<Animal>因为现在 T 是 Object 而集合是基于 Animal 的。如果你的方法签名有Collection<? extends T>,我认为这可能有效。

于 2011-12-03T14:08:30.720 回答