Java 泛型方法/参数类型

发布于 2024-12-19 11:31:57 字数 2870 浏览 1 评论 0原文

在以下代码示例中:

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

In the following code example:

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

}

Why does the compiler allow the call to the genericFromArrayToCollection() method only if the declared type of the collection is the parent of the declared type of the array (See lines marked #2, #3 and #4) . Why is this please?

Thanks

Edit

When i uncomment the line marked #4 i get the following error

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

Edit 2

@Tudor i tried the following method using this statement

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

The compiler complained with an error saying that cannot be applied to java.util.ArrayList

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

殤城〤 2024-12-26 11:31:57

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

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[]< /code> 数组,因为 Object 不是 Animal 的子类型。

To answer your question, let's first establish the premise: we know that if you have a method taking an array as a parameter, you can pass an array of a subtype:

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

but the reverse is not true:

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

Then, it boils down to how the parameters of a generic method are actually instantiated, that is how the parameter type inference works. In your case #3, it is inferred to Animal, so the method declaration really looks like:

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

and since Dog is a subtype of Animal, it can fit nicely instead of the Animal[] array. Same for case #2.

However, in case #4, the type is inferred to be Animal again, so the method looks like above, but you cannot put an Object[] array in place of an Animal[] array because Object is not a subtype of Animal.

狂之美人 2024-12-26 11:31:57

因此,作为方法参数提供的静态类型按顺序排列:

For forArrayToCollection

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

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

对于genericFromArrayToCollection

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

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

在所有情况下,T 必须替换集合的通用参数。前两个调用完全匹配。对于第三次调用,TObject,并且由于 Java 中数组的行为方式很奇怪,Animal[] 可以分配给 < code>Object[] (但如果您尝试在其中存储 NumberFormat,您将得到未经检查的 ArrayStoreException)。同样,对于第四个,可以将 Dog[] 分配给 Animal[]。对于最后一个 Object[] 不能分配给 Animal[] (从数组读取永远不应该抛出 ClassCastException 除非你做了一些对于通用数组转换怪物来说是不健全的(你会得到一个 javac 警告 - 记下它))。

So the static types you are giving as arguments to the method are in order:

For forArrayToCollection.

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

This method has parameter types Animal[], Collection<Animal>. First call matched exactly. Second call attempts to assign a Collection<Animal> to Collection<Dog> which is wrong (I can add a Cat to a Collection<Animal>, which I shouldn't be able to do to a Collection<Dog>).

For genericFromArrayToCollection.

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

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

In all cases, T must substitute for the generic argument of the collection. First two calls match exactly. For the third call, T is Object and, because of the odd way arrays behave in Java, Animal[] can be assigned to an Object[] (but you'll get an unchecked ArrayStoreException if you try to store a NumberFormat in it). Similarly, for the fourth, Dog[] can be assigned to Animal[]. For the last Object[] cannot be assigned to Animal[] (reads from an array should never throw a ClassCastException unless you've done some unsound with a generic array cast monstrosity (you'll get a javac warning - take note of it)).

屌丝范 2024-12-26 11:31:57

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

basically, genericFromArrayToCollection() defines T as a type parameter and that is used to define the 2 method parameters (i.e. T[] a and Collection<T> c). Both a and c must be based on the same type, so Dog[] and Collection<Dog> would work, Animal[] and Collection<Animal> would work, but Object[] and Collection<Animal> would not, because now T is Object whereas the collection is based on Animal. Had your method signature had Collection<? extends T>, this may have worked I think.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文