代码之家  ›  专栏  ›  技术社区  ›  Ashish Agarwal

无界通配符类型列表有什么区别?>原始类型列表呢?

  •  23
  • Ashish Agarwal  · 技术社区  · 15 年前

    你能帮我了解一下 无限通配符类型列表 原始类型列表 ?

    List<?> b;    // unbounded wildcard type
    List a;       // raw type
    


    除此之外,还有谁能帮助我理解什么是 有界类型参数列表 ?

    List<E extends Number> c;
    
    3 回复  |  直到 8 年前
        1
  •  32
  •   John Feminella    15 年前

    以下是三个方面的总结:

    • List :没有类型参数的列表。它是一个元素属于任何类型的列表-- 元素可以是不同类型的 .

    • List<?> :具有未绑定类型参数的列表。其元素属于特定但未知的类型; 元素的类型必须相同 .

    • List<T extends E> :一个名为 T . 为提供的类型 T 必须是扩展的类型 E 或者它不是参数的有效类型。

        2
  •  18
  •   Tom    12 年前

    你应该看看有效的Java,第23项:不要在新代码中使用原始类型。

    要使用该书中的示例,请考虑以下示例…如果您有一个集合,而您不关心其中的元素类型,该怎么办?例如,要查看两个集合之间有多少个元素是相同的。您可能会想到以下几点:

    public static int numElementsInCommon(Set s1, Set s2) {
      int result = 0;
      for (Object o : s1) {
        if (s2.contains(o)) {
          ++result;
        }
      }
      return result;
    }
    

    这个示例在工作时,由于使用了原始类型,所以不适合使用。原始类型根本不安全…您可能会以一种不安全类型的方式修改该集并损坏您的程序。相反,请谨慎行事,并使用类型安全的替代方法:

    public static int numElementsInCommon(Set<?> s1, Set<?> s2) {
      int result = 0;
      for (Object o : s1) {
        if (s2.contains(o)) {
          ++result;
        }
      }
      return result;
    }
    

    区别在于你只能添加 null 到A Set<?> ,并且您不能假设您从 SET & LT?gt; . 如果你用生的 Set ,您可以添加任何您想要的内容。这个 numElementsInCommon 方法是一个很好的例子,您甚至不需要添加任何内容,也不需要假设集合中的内容。这就是为什么它是使用 ? 通配符。

    希望这有帮助。在有效的Java中读取整个项目,这将变得非常清楚。

    回答问题的第二部分…记住,当你使用 ? 通配符,您不能假定您从集合中取出的元素的任何内容?如果您确实需要对从集合中移除的对象的接口进行假设,该怎么办?例如,假设您希望跟踪 Cool 东西。

    public interface Cool {
      // Reports why the object is cool
      void cool();
    }
    

    然后您可能会得到如下代码:

    public static void reportCoolness(Set s) {
      for (Object item : s) {
        Cool coolItem = (Cool) item;
        coolItem.cool();
      }
    }
    

    这不是类型安全的…你需要确保你通过了一个只有 物体。要修复它,您可以说:

    public static void reportCoolness(Set<Cool> s) {
      for (Cool coolItem : s) {
        coolItem.cool();
      }
    }
    

    这太棒了!完全符合您的要求,并且类型安全。但如果以后你有了这个呢:

    public interface ReallyCool extends Cool {
      // Reports why the object is beyond cool
      void reallyCool();
    }
    

    既然所有 ReallyCool 对象是 ,您应该能够执行以下操作:

    Set<ReallyCool> s = new HashSet<ReallyCool>();
    // populate s
    reportCoolness(s);
    

    但是您不能这样做,因为泛型具有以下属性:假设 B 是的子类 A 然后 Set<B> 不是的子类 Set<A> . 这方面的技术术语是“泛型类型是不变的”(与协变相反)。

    要使最后一个示例生效,您需要创建一个 Set<Cool> 通过在 Set<ReallyCool> . 为了避免让您的API客户机经历这些讨厌的、不必要的代码,您只需 reportCoolness 更灵活的方法如下:

    public static void reportCoolness(Set<? extends Cool> s) {
      for (Cool coolItem : s) {
        coolItem.cool();
      }
    }
    

    现在你的方法需要 集合 包含以下元素的 或任何子类 . 所有这些类型都遵循 应用程序编程接口。。。所以我们可以安全地呼叫 cool() 任何元素的方法

    有道理?希望这有帮助。

        3
  •  4
  •   akf    15 年前

    在第一个问题上, List List<?> :

    两者之间的一个显著区别是,当您使用通配符作为类型时, Collection 是未知的,所以 add 方法将引发编译时错误。

    您仍然可以从 名单&?gt; 但是你需要一个明确的演员表。