难以理解通配符

时间:2017-07-02 08:20:13

标签: java generics wildcard

public static void reverse(List<?> list) 
{ 
List<Object> tmp = new ArrayList<Object>(list);
for (int i = 0; i < list.size(); i++) 
{

list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ? 

}

}

我正在学习泛型。 我知道这个:当使用通配符时?被适当的类型取代。当调用reverse()方法时?将被替换,因为每个类型都是Object的子类型,所以不应该有错误。 我正在寻找一个清晰的解释。请帮忙。

3 个答案:

答案 0 :(得分:1)

您可以将任何List<SomeType>作为reverse参数传递给List<?> list方法,编译器应该只允许您向{{1}添加SomeType的元素}}

例如,它可以是ListList<String>等......

因此List<Ineger>无法工作,因为编译器不知道传递给方法的实际list.set支持的元素类型。它不知道List<?> list的元素来自同一个List<Object> tmp(因此可以安全地添加到它中)。

编写方法的正确方法是定义泛型类型参数:

list

现在编译器知道public static <T> void reverse(List<T> list) { List<T> tmp = new ArrayList<> (list); for (int i = 0; i < list.size(); i++) { list.set(i, tmp.get(list.size()-i-1)); } } list都包含相同类型的元素。

答案 1 :(得分:0)

Generics work in this way

这里:

public static void reverse(List<?> list) 

由于我们不知道list的元素类型代表什么,我们无法向其添加对象。

这里:

List<Object> tmp = new ArrayList<Object>(list);
  ...
list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ? 

您在Object中添加List,其中绝对内容可能包含不同类型的元素。
在你的情况下,你写的不是这样的:

List<Object> tmp = new ArrayList<Object>(list);

但编译器不会通过尝试理解代码的逻辑来使异常 因为否则它应该检查整个代码并且编译器错误消息可能非常复杂 例如,假设您在代码中一次add tmp.set(0, "aa");

答案 2 :(得分:0)

List<?>是未知类型的列表,我们不知道此列表中的 type ,引入了泛型以删除运行时类型转换异常并给出安全性。您无法使用undefined contains向集合中添加任何类型,因为您将破坏它。示例是否允许:

    List<Dog> dogs = new ArrayList<>(Arrays.asList(new Dog("dog")));

    public doSomething(List<?> notKnownType) {
        notKnownType.add(new Cat("cat"));   
// if this ok or not? <?> is not known type, all types have Object as parent let's add Cat
    }

    for (Dog dog : dogs) {
        System.out.println(dog); //ClassCastException
    }

ClassCastExceptin因为我们将猫添加到狗并将每只狗都投入到猫中,因此在运行时不存在 和所有集合等包含对象。 这行将在编译之后:

for (Object dog : dogs) {
    System.out.println((Dog) dog); //ClassCastExceptin 
}

不允许这样你就无法在未知类型集合中添加内容并在此处获得编译时错误list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ?