考虑下面的通用方法程序:
class GenericTest {
int i;
}
public class GenericMethod {
public <T> List<T> addList(T t, T t1) {
List<T> list=new ArrayList<T>();
list.add(t);
list.add(t1);
return list;
}
public <T> List<T> addList(T t, T t1, List<T> l) {
List<T> list=new ArrayList<T>();
list.add(t);
list.add(t1);
list.addAll(l);
return list;
}
public static void main(String[] args) {
GenericMethod gm=new GenericMethod();
List l=gm.addList(new Integer(42), "java"); //Line 21
System.out.println(l);
List<Object> list = new ArrayList<Object>();
list.add(false);
List l2 = gm.addList("java", new Integer(42), list); //Line 25
System.out.println(l2);
GenericTest gt = new GenericTest();
List l3 = gm.addList("java", gt); //Line 28
System.out.println(l3);
List l4 = gm.addList(gm, gt); //Line 30
System.out.println(l4);
List lst = new ArrayList();
lst.add(new Object());
List l5 = gm.addList("java", new Integer(42), lst); //Line 34
System.out.println(l5);
System.out.println(l5.get(0));
}
}
通过参考链接Java Generics – Confusing behavior,我推断,
在第21行,因为该方法是使用String和Integer调用的,所以它使用Object for T调用方法.对于第25行也是如此,因为List也有类型Object,它使用Object for T调用方法.使用其他类型的Calling List将产生错误.我的推论是否正确?
我无法想到的是
1)传递String和类时的第28行,
2)当两个不同的班级通过时,第30行,
3)当没有类型声明的List作为参数传递时的第34行.
任何人都可以分享他们的知识来清除我的理解任何帮助,将不胜感激!谢谢!
最佳答案
Calling List with other type will produce an error. Is my inference correct?
是;你无法传递List< String>例如,那里.通常,第二个addList方法的意图是错误的.正确的签名是这样的:
public <T> List<T> addList(T t1, T t2, List<? extends T> list)
请注意?扩展语法.如果从列表中读取所有内容,则没有理由不添加它. T的某个特定子类型的列表保证包含Ts.这有什么不同的原因:如果你想添加到这个列表怎么办?假设T是Number,你传入一个Integer列表.双是一个数字.使用List< T>列表,您可以调用list.add(5.0),它将编译并运行,将双精度放入您的整数列表.使用List<?扩展T> ;,添加调用始终是编译器错误(除非您尝试添加null,这将起作用).对于阅读,你得到一个T out,无论你是否打电话给列表<?延伸T>或者列表< T>,没关系.
1) Line 28 when String and class is passed,
不,您正在传递String类型的实例和GenericTest类型的实例. String和GenericTest一样是一个类.字符串并不特别.这与第21行中的调用完全相同:您传递了2个表达式;对象类型X之一和对象类型Y中的另一个.因此,T被推断为2个传递实例之间最特定的共享类型(可能是所谓的lub类型:一组类型).在第21行的情况下,Integer和String最具体的共享类型只是Object(技术上,实际上是它的lub类型Object& Serializable,但这里大多数并不重要).在第28行中,它是String和GenericTest之间最具体的共享类型,它仍然是Object,没有区别.
2) Line 30 when two different class is passed,
往上看;恰恰相同的情况. GenericTest和GenericMethod之间最具体的共享类型是Object.
3) Line 34 when List declared without type is passed as argument.
第34行中的表达式lst是’raw’类型ArrayList.当你使用原始类型时,会发生两件事:[1]编译器会警告你你正在使用原始类型,并且[2]几乎所有泛型测试和检查都禁用任何涉及任何原始类型的调用,因此,编译器只会让这种情况发生.
请记住,泛型是编译器想象力的一个虚构.他们的观点是编译器告诉您代码已损坏.就这样.