有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java难以理解通配符

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()方法?将被替换,因为每个类型都是对象的子类型,所以不应该有错误。 我在寻找一个非常清楚的解释。请帮忙


共 (3) 个答案

  1. # 1 楼答案

    List<?>是未知类型的列表,我们不知道该列表中的类型,引入了泛型来删除运行时类型转换异常并提供安全性。您无法向包含未定义的集合添加任何类型,因为您将破坏它。例如,如果允许:

        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,因为我们将cat添加到dogs,并将每个dog转换为cat,运行时不存在泛型 所有集合等都包含对象。 这一行将在编译后出现:

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

    对于not allow this,您无法向未知类型集合添加某些内容,并在此处获取编译时错误list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ?

  2. # 2 楼答案

    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 ? 
    

    List中添加Object,在绝对值中可以包含不同类型的元素
    就你而言,情况并非如你所写:

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

    但是编译器不会因为试图理解代码的逻辑而破例
    因为否则它应该检查整个代码,编译器错误消息可能会非常复杂
    例如,假设您在代码中的某个时间add tmp.set(0, "aa");

  3. # 3 楼答案

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

    例如,它可以是一个List<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));
        }
    }
    

    现在编译器知道listtmp都包含相同类型的元素