之间有什么区别List,List<?>,List<T>,List<E>,和List<Object>?
现在我不要盲目地问这个问题,所以请不要关闭这个帖子.我先介绍一下基本代码:
public static void test(List<?> list){
System.out.println(list); // Works
}
Run Code Online (Sandbox Code Playgroud)
我明白:
1 List.:是原始类型,因此不是typesafe.它只会在强制转换时生成运行时错误.当演员表不好时我们想要编译时错误.不建议使用.
2 . List<?>:是一个无界的通配符.但不确定这是为了什么?所以如果我改变List<?>方法
public static void test(List<?> list){
list.add(new Long(2)); // Error
list.add("2"); // Error
System.out.println(list);
}
Run Code Online (Sandbox Code Playgroud)
它仍然很好.如果您能解释一下这种用法,我将不胜感激.
编辑:如果我这样做:
public static void test(List<T> list){ // T cannot be resolved
System.out.println(list);
}
Run Code Online (Sandbox Code Playgroud)
但如果我改成List<?>这个:
public <T> T[] toArray(T[] a){
return a;
}
Run Code Online (Sandbox Code Playgroud)
3 . <T>:
public static void test(List<Object> list){
System.out.println(list);
}
Run Code Online (Sandbox Code Playgroud)
我想我不明白这种语法.我看到这样的东西,它有效:
test((List<Object>) names);
Run Code Online (Sandbox Code Playgroud)
请帮我解释一下吗?有时候,我看到的<E>,或者<U>,或者<T,E>,test(List<Object>).它们是一样的还是代表不同的东西?
4.List<String>
public static void test(List<?> list){
System.out.println(list); // Works
}
Run Code Online (Sandbox Code Playgroud)
然后我得到List<String>了以下代码的错误.我很迷惑.我以为List<Object>是其中的一部分String?
public static void test(List<?> list){
list.add(new Long(2)); // Error
list.add("2"); // Error
System.out.println(list);
}
Run Code Online (Sandbox Code Playgroud)
编辑:如果我试试这个
public static void test(List<T> list){ // T cannot be resolved
System.out.println(list);
}
Run Code Online (Sandbox Code Playgroud)
然后我得到了 Object
Kaj*_*Kaj 76
1)正确
2)您可以将其视为"只读"列表,您不关心项目的类型.例如,可以由返回列表长度的方法使用.
3)T,E和U是相同的,但人们倾向于使用例如T代表类型,E代表元素,V代表值,K代表密钥.编译的方法表示它采用了某种类型的数组,并返回相同类型的数组.
4)你不能混合橙子和苹果.如果可以将字符串列表传递给期望对象列表的方法,则可以将String添加到String列表中.(并非所有对象都是字符串)
Far*_*ker 26
对于最后一部分:尽管String是Object的子集,但List <String>不是从List <Object>继承的.
Ted*_*opp 20
符号的List<?>意思是"一个东西的列表(但我不是说什么)".由于代码test适用于列表中的任何类型的对象,因此它可用作形式化方法参数.
使用类型参数(如第3点所述),需要声明type参数.它的Java语法是放在<T>函数前面.这与在方法体中使用名称之前将形式参数名称声明为方法完全类似.
关于List<Object>不接受a List<String>,这是有道理的,因为a String不是Object; 它是的子类Object.修复是声明public static void test(List<? extends Object> set) ....但那extends Object是多余的,因为每个类都直接或间接地扩展Object.
Pet*_*ter 13
你可以不投之所以List<String>要List<Object>的是,它可以让你违反的制约List<String>.
考虑以下场景:如果我有一个List<String>,它应该只包含类型的对象String.(这是一final堂课)
如果我可以将其转换为a List<Object>,则允许我添加Object到该列表,从而违反原始合同List<String>.
因此,一般来说,如果类C继承自类P,则不能说GenericType<C>也继承自GenericType<P>.
NB我在之前的回答中已经对此进行了评论,但希望扩展它.
在第三点,"T"无法解析,因为它未声明,通常在声明泛型类时,您可以使用"T"作为绑定类型参数的名称,许多在线示例(包括oracle的教程)使用"T"作为类型参数的名称,例如,您声明一个类,如:
public class FooHandler<T>
{
public void operateOnFoo(T foo) { /*some foo handling code here*/}
}
Run Code Online (Sandbox Code Playgroud)
你说这个FooHandler's operateOnFoo方法需要一个类型为"T"的变量,它在类声明本身上声明,考虑到这一点,你可以稍后再添加另一个方法
public void operateOnFoos(List<T> foos)
Run Code Online (Sandbox Code Playgroud)
在T,E或U的所有情况下都有类型参数的所有标识符,你甚至可以有多个使用语法的类型参数
public class MyClass<Atype,AnotherType> {}
Run Code Online (Sandbox Code Playgroud)
虽然有效地将Sting作为Object的子类型,但在泛型类中没有这样的关系,List<String>不是List<Object>从编译器的角度来看它们是两种不同类型的子类型,这在本博客条目中得到了最好的解释
让我们在Java历史的背景下谈论它们;
List: 列表意味着它可以包含任何对象。列表在Java 5.0之前的版本中;Java 5.0引入了List,以实现向后兼容。
List list=new ArrayList();
list.add(anyObject);
Run Code Online (Sandbox Code Playgroud)
List<?>: ?表示未知对象而不是任何对象;通配符?介绍用于解决“通用类型”构建的问题;看到通配符 ; 但这还会导致另一个问题:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Run Code Online (Sandbox Code Playgroud)
List< T> List< E> 表示在项目Lib中没有T或E类型的前提下的通用声明。
List< Object> 表示通用参数化。理论
String[] 可以投射到 Object[]
但
List<String>无法转换为List<Object>。
实践
对于列表,它比那要微妙得多,因为在编译时,不会检查传递给方法的List参数的类型。方法定义也可以这么说List<?>-从编译器的角度来看,它是等效的。这就是OP的示例#2给出运行时错误而不是编译错误的原因。
如果您List<Object>谨慎处理传递给方法的参数,从而不对列表的任何元素进行类型检查,则可以使用定义方法,List<Object>但实际上可以List<String>从调用代码中接受参数。
答: 因此,此代码不会产生编译或运行时错误,并且实际上(也许令人惊讶?)可以工作:
public static void main(String[] args) {
List argsList = new ArrayList<String>();
argsList.addAll(Arrays.asList(args));
test(argsList); // The object passed here is a List<String>
}
public static void test(List<Object> set) {
List<Object> params = new ArrayList<>(); // This is a List<Object>
params.addAll(set); // Each String in set can be added to List<Object>
params.add(new Long(2)); // A Long can be added to List<Object>
System.out.println(params);
}
Run Code Online (Sandbox Code Playgroud)
B. 此代码将给出运行时错误:
public static void main(String[] args) {
List argsList = new ArrayList<String>();
argsList.addAll(Arrays.asList(args));
test1(argsList);
test2(argsList);
}
public static void test1(List<Object> set) {
List<Object> params = set; // Surprise! Runtime error
}
public static void test2(List<Object> set) {
set.add(new Long(2)); // Also a runtime error
}
Run Code Online (Sandbox Code Playgroud)
C. 此代码将给出运行时错误(java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[]):
public static void main(String[] args) {
test(args);
}
public static void test(Object[] set) {
Object[] params = set; // This is OK even at runtime
params[0] = new Long(2); // Surprise! Runtime error
}
Run Code Online (Sandbox Code Playgroud)
在B中,参数在编译时set不是类型化的List:编译器将其视为List<?>。存在运行时错误,因为在运行时set会变成从中传递的实际对象main(),即为List<String>。List<String>无法将A 强制转换为List<Object>。
在C中,参数set需要一个Object[]。以String[]对象作为参数调用时,没有编译错误,也没有运行时错误。那是因为String[]强制转换为Object[]。但是接收到的实际对象test()仍然是String[],它没有改变。因此,params对象也变为String[]。而且a的元素0 String[]不能分配给Long!
(希望我在这里掌握了所有内容,如果我的推理是错误的,我敢肯定社区会告诉我。更新:我已经更新了示例A中的代码,以使它可以实际编译,同时仍然显示出要点。)
| 归档时间: |
|
| 查看次数: |
147039 次 |
| 最近记录: |