Java通用方法/参数类型

时间:2011-12-03 12:18:47

标签: java generics scjp ocpjp

在以下代码示例中:

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 个答案:

答案 0 :(得分:1)

因此,您提供的静态类型作为方法的参数依次为:

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[](但是您可以如果您尝试在其中存储ArrayStoreException,请取消选中NumberFormat。同样,对于第四个,Dog[]可以分配给Animal[]。对于最后一个Object[]无法分配给Animal[](从数组中读取的内容永远不会抛出ClassCastException,除非您使用通用数组投射怪物做了一些不合理的事情(你&#39} ;得到一个javac警告 - 注意它))。

答案 1 :(得分: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) {

由于DogAnimal的子类型,因此它可以很好地适合而不是Animal[]数组。情况#2相同。

但是,在#4的情况下,类型被再次推断为Animal,因此该方法如上所示,但您不能放置Object[]数组来代替Animal[]数组,因为{{ 1}}不是Object的子类型。

答案 2 :(得分:1)

基本上,genericFromArrayToCollection()将T定义为类型参数,用于定义2个方法参数(即T[] a和Collection<T> c)。 a和c都必须基于相同的类型,因此Dog[]Collection<Dog>可行,Animal[]Collection<Animal>可行,但Object[]和{{ 1}}不会,因为现在T是Object而收集是基于Animal。如果你的方法签名有Collection<Animal>,我认为这可能有用。