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;
}
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为了回答你的问题,我们首先建立一个前提:我们知道,如果你有一个以数组作为参数的方法,你可以传递一个子类型的数组:
但反之则不然:
然后,它归结为如何泛型方法的参数实际上是实例化的,这就是参数类型推断的工作原理。在您的情况 #3 中,它被推断为 Animal,因此方法声明实际上如下所示:
并且由于
Dog
是Animal
的子类型,因此它可以很好地适合而不是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:
but the reverse is not true:
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:
and since
Dog
is a subtype ofAnimal
, it can fit nicely instead of theAnimal[]
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 anAnimal[]
array becauseObject
is not a subtype ofAnimal
.因此,作为方法参数提供的静态类型按顺序排列:
For
forArrayToCollection
。此方法具有参数类型
Animal[]、Collection
。第一次通话完全匹配。第二次调用尝试将Collection
分配给Collection
这是错误的(我可以将Cat
添加到Collection
,我不应该对Collection
执行此操作)。对于
genericFromArrayToCollection
。在所有情况下,
T
必须替换集合的通用参数。前两个调用完全匹配。对于第三次调用,T
是Object
,并且由于 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
.This method has parameter types
Animal[], Collection<Animal>
. First call matched exactly. Second call attempts to assign aCollection<Animal>
toCollection<Dog>
which is wrong (I can add aCat
to aCollection<Animal>
, which I shouldn't be able to do to aCollection<Dog>
).For
genericFromArrayToCollection
.In all cases,
T
must substitute for the generic argument of the collection. First two calls match exactly. For the third call,T
isObject
and, because of the odd way arrays behave in Java,Animal[]
can be assigned to anObject[]
(but you'll get an uncheckedArrayStoreException
if you try to store aNumberFormat
in it). Similarly, for the fourth,Dog[]
can be assigned toAnimal[]
. For the lastObject[]
cannot be assigned toAnimal[]
(reads from an array should never throw aClassCastException
unless you've done some unsound with a generic array cast monstrosity (you'll get a javac warning - take note of it)).基本上, genericFromArrayToCollection() 将 T 定义为类型参数,并用于定义 2 个方法参数(即可以工作,但是
T[]
a 和Collection
c)。 a 和 c 必须基于相同的类型,因此Dog[]
和Collection
可以工作,Animal[]
和 < code>CollectionObject[]
和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 andCollection<T>
c). Both a and c must be based on the same type, soDog[]
andCollection<Dog>
would work,Animal[]
andCollection<Animal>
would work, butObject[]
andCollection<Animal>
would not, because now T is Object whereas the collection is based on Animal. Had your method signature hadCollection<? extends T>
, this may have worked I think.