以下代码甚至可以编译怎么可能?据我所知,count函数是用两种不同的类型调用的,但编译器没有抱怨并且很乐意编译这段代码。
public class Test {
public static <T> int count(T[] x,T y){
int count = 0;
for(int i=0; i < x.length; i++){
if(x[i] == y) count ++;
}
return count;
}
public static void main(String[] args) {
Integer [] data = {1,2,3,1,4};
String value = "1";
int r =count(data,value);
System.out.println( r + " - " + value);
}
}
答案 0 :(得分:7)
T
被强制向上Object
。 Integer[]
可以上传至Object[]
,String
上传至Object
,并且可以进行类型检查。
答案 1 :(得分:2)
在这种情况下,T
没用。您可以将签名更改为public static int count(Object[] x, Object y)
,而不会影响编译器允许它接受的参数。 (您可以看到Arrays.fill()
的签名使用该签名作为签名。)
如果我们考虑更简单的情况,你只有T
类型的参数,你可以看到,因为T
的任何实例也是其超类的实例,T
总是可以推断为它的上限,它仍然会接受与以前相同的参数类型。因此,我们可以摆脱T
并使用其上限(在本例中为Object
)。
Java中的数组工作方式相同:数组是协变的,这意味着如果S
是T
的子类,S[]
是T[]
的子类。因此,上述相同的论点适用 - 如果您只有类型T
和T[]
的参数,T
可以替换为其上限。
(请注意,这不适用于非协变或逆变的泛型类型:List<S>
不是List<T>
的子类型。)
答案 2 :(得分:2)
如果您将通话更改为:
int r = Test.<Integer>count(data, value);
你会看到编译器抱怨。
答案 3 :(得分:1)
通过一次传递两个对象,您在T
上设置了太多限制。这会“强制”编译器推断Object
。幸运的是,有一个简单的解决方法 - 只传递一个对象。以下内容将产生预期的错误。
public static void main(String[] args) {
Integer[] data = { 1, 2, 3, 4 };
String value = "1";
int r = count(value).in(data);
System.out.println(r + " - " + value);
}
public static <T> Counter<T> count(T obj) {
return new Counter<T>(obj);
}
public static class Counter<T> {
private final T obj;
Counter(T obj) {
this.obj = obj;
}
public int in(T[] array) {
return in(Arrays.asList(array));
}
public int in(Iterable<? extends T> iterable) {
int count = 0;
for (T element : iterable) {
if (element == obj) {
++count;
}
}
return count;
}
}
答案 4 :(得分:0)
类型没有那么不同 - 两者都是java.lang.Object的子类。因此编译器假设在这种情况下T是Object。