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

基本的に、genericFromArrayToCollection() は T を型パラメーターとして定義し、それを使用して 2 つのメソッド パラメーター (つまりT[]a とCollection<T>c) を定義します。a と c はどちらも同じ型に基づいている必要があるためDog[]、 とCollection<Dog>は機能し、Animal[]Collection<Animal>は機能しますが、Object[]とは機能Collection<Animal>しません。これは、T が Object であるのに対し、コレクションは Animal に基づいているためです。メソッドの署名がCollection<? extends T>だった場合、これはうまくいったと思います。

于 2011-12-03T14:08:30.720 に答える
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[]ObjectAnimal

于 2011-12-03T12:58:07.503 に答える
1

したがって、メソッドに引数として与える静的型は次のとおりです。

のためforArrayToCollectionに。

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

このメソッドにはパラメーターの型がありますAnimal[], Collection<Animal>。最初の呼び出しは正確に一致しました。2 番目の呼び出しは、間違った a を割り当てようとします ( a に a を追加することはできCollection<Animal>ますが、これをaに追加することはできません)。Collection<Dog>CatCollection<Animal>Collection<Dog>

のためgenericFromArrayToCollectionに。

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

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

いずれの場合も、Tコレクションのジェネリック引数を置き換える必要があります。最初の 2 つの呼び出しは正確に一致します。3 番目の呼び出しでは、Tis Objectand は、Java での配列の動作が奇妙であるため、Animal[]an に割り当てることができます (ただし、a を格納しようとするとObject[]、チェックが外されます)。同様に、4 番目については、に割り当てることができます。最後の代入はできません(配列からの読み取りは、一般的な配列キャストの怪物で不健全なことをしない限り、決してスローするべきではありません(javac警告が表示されます-注意してください))。ArrayStoreExceptionNumberFormatDog[]Animal[]Object[]Animal[]ClassCastException

于 2011-12-03T12:53:05.600 に答える