为什么我们在使用List
而不是在使用List<Object>
时会失去类型安全?它们基本上不是一回事吗?
编辑:我发现以下内容给出了编译错误
public class TestClass
{
static void func(List<Object> o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
而这不是
public class TestClass
{
static void func(List o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
为什么?
答案 0 :(得分:5)
为什么我们在使用
List
而不是在使用List<Object>
时会失去类型安全?它们基本上不是一回事吗?
不,他们不是一回事。
如果您要提供API,
class API {
static List<Object> getList() { ... }
static void modifyList(List<Object> l) { ... }
}
并且客户端使用它不正确
List<Integer> list = API.getList();
API.modifyList(list);
for (Integer i : list) { ... } // Invalid
然后,当您的API指定List<Object>
时,他们会收到编译时错误,但是当API.getList()
返回List
并且API.modifyList(list)
需要{{1}时,它们就不会没有泛型类型参数。
编辑:
在评论中你提到了改变
List
到
void func(List<Object> s, Object c) { s.add(c); }
这样
void func(List s, Object c) { s.add(c); }
会起作用。
这违反了类型安全。这种类型安全的方法是
func(new List<String>(), "");
基本上说<T> void func(List<? super T> s, T c) { s.add(c); }
是一个参数化函数,它接受一个func
类型可以是任何超类T,一个类型为T,并将值添加到列表中。
答案 1 :(得分:5)
List
是某些您不知道的类型的列表。它可以是List<String>
,List<Integer>
等
它实际上等同于List<?>
或List<? extends Object>
,但不记录该事实。它仅支持向后兼容性。
List<Object>
是一个对象列表。 任何类型的任何对象都可以放在其中,与List<String>
相反,例如,它只接受字符串。
所以不,他们不是一回事。
答案 2 :(得分:3)
List<Object>
实际上并不比List
更安全。但是,代码中的Object
确实意味着意图。当其他人稍后查看它时,他们可以看到您故意选择Object
作为类型,而不是想知道您是否忘记放置类型或存储其他内容并将其类型化为其他地方。
由于代码的读取次数超过了写入次数,因此稍后对代码意图的提示非常有价值。
答案 3 :(得分:1)
当您使用List
而不是List<Object>
时有编译器警告的原因是当您有List
时,编译器不知道它是什么类型的List,所以虽然您可以将其视为List<Object>
,但编译器无法确保在代码中的某个其他位置未将其设置为引用List<String>
并且无法检查泛型的类型安全性。这实际上是编译器警告 - 它说它不能帮助确保泛型的类型安全性,并且它也不会在运行时发生(直到稍后在代码中存在实际的强制转换)。 / p>
答案 4 :(得分:0)
就目的而言,你可以说它们是一样的。但是大概你几乎从来没有用List
的纯实例填充Object
。他们是String
或其他什么。在这个例子中,List<Object>
在技术上使用泛型,但并没有真正利用它。因此,它丢失了泛型的编译时类型检查。
答案 5 :(得分:0)
Type Erasure是一个答案,并且与Java 1.5之前的版本具有向后兼容性,如果是第一个,则更加严格。
泛型被引入Java语言,以在编译时提供更严格的类型检查并支持泛型编程。为了实现泛型,Java编译器将类型擦除应用于:
将通用类型中的所有类型参数及其边界或对象替换为无边界的对象。因此,产生的字节码仅包含普通的类,接口和方法。 必要时插入类型转换,以保持类型安全。 生成桥接方法以在扩展的泛型类型中保留多态。 类型擦除可确保不会为参数化类型创建新的类;因此,泛型不会产生运行时开销。