在以下代码示例中:
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
@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;
}
答案 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
必须替换集合的泛型参数。前两个电话完全匹配。对于第三个调用,T
为Object
,并且由于数组在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) {
由于Dog
是Animal
的子类型,因此它可以很好地适合而不是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>
,我认为这可能有用。