有 Java 编程相关的问题?

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

Java泛型方法/参数类型

在以下代码示例中:

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;
}

共 (3) 个答案

  1. # 1 楼答案

    基本上,genericFromArrayToCollection()将T定义为一个类型参数,用于定义两个方法参数(即T[]a和Collection<T>c)。a和c都必须基于相同的类型,所以Dog[]Collection<Dog>会起作用,Animal[]Collection<Animal>会起作用,但Object[]Collection<Animal>不会,因为现在T是对象,而集合是基于动物的。如果你的方法签名有Collection<? extends T>,我想这可能已经奏效了

  2. # 2 楼答案

    因此,您作为方法参数给出的静态类型的顺序如下:

    对于forArrayToCollection

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

    此方法具有参数类型Animal[], Collection<Animal>。第一个电话完全吻合。第二个调用尝试将Collection<Animal>分配给Collection<Dog>,这是错误的(我可以将Cat添加到Collection<Animal>,这是我不能对Collection<Dog>执行的)

    对于genericFromArrayToCollection

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

    在所有情况下,T必须替换集合的泛型参数。前两个电话完全匹配。对于第三个调用,TObject,由于Java中数组的行为方式很奇怪,Animal[]可以分配给Object[](但如果试图在其中存储NumberFormat,则会得到一个未经检查的ArrayStoreException)。类似地,对于第四个,可以将Dog[]分配给Animal[]。最后一个例子是Object[]不能被分配给Animal[](从数组中读取的数据永远不应该抛出ClassCastException,除非你用一个通用数组强制转换怪物做了一些不合理的操作(你会得到一个javac警告——请注意)

  3. # 3 楼答案

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

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

    但事实并非如此:

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

    然后,它归结为泛型方法的参数实际上是如何实例化的,也就是参数类型推理的工作方式。在你的例子#3中,它被推断为动物,所以方法声明看起来真的像:

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

    由于DogAnimal的一个子类型,它可以很好地代替Animal[]数组。第二种情况也是如此

    然而,在案例#4中,该类型又被推断为动物,因此该方法如上所示,但不能用Object[]数组代替Animal[]数组,因为Object不是Animal的子类型