Skip to content

Latest commit

 

History

History
102 lines (76 loc) · 4.95 KB

04_Generic_Methods_and_Varargs.md

File metadata and controls

102 lines (76 loc) · 4.95 KB

《《《 返回首页
《《《 上一节

泛型方法和可变参数

这是接受任何类型的数组并将其转换为列表的方法:

  class Lists {
    public static <T> List<T> toList(T[] arr) {
      List<T> list = new ArrayList<T>();
      for (T elt : arr) list.add(elt);
        return list;
      }
    }

静态方法 toList 接受一个 T[] 类型的数组并返回一个类型列表 List<T>,并且对于任何类型 T 都这样做。这通过在开头写入<T>来指示方法签名,它将 T 声明为一个新的类型变量。 一种方法用这种方式声明一个类型变量被称为泛型方法。 类型的范围变量 T 对于方法本身是本地的; 它可能出现在方法签名和方法 体,但不在方法之外。

该方法可以如下调用:

  List<Integer> ints = Lists.toList(new Integer[] { 1, 2, 3 });
  List<String> words = Lists.toList(new String[] { "hello", "world" });

在第一行中,装箱将 int1,2,3 转换为 Integer

将参数打包到一个数组中是非常麻烦的。 对于方法的最后一个参数是数组的情况,可变参数特性允许使用一种特别的、更方便的语法。 要使用这个特性,我们在方法声 明中用 T... 替换 T[]:  

  class Lists {
    public static <T> List<T> toList(T... arr) {
    List<T> list = new ArrayList<T>();
    for (T elt : arr) list.add(elt);
      return list;
    }
  }

现在该方法可以被调用,如下所示:

  List<Integer> ints = Lists.toList(1, 2, 3);
  List<String> words = Lists.toList("hello", "world");

这只是我们上面写的内容的简写。 在运行时,参数就像以前一样被打包到传递给方法的数组中。

任何数量的参数都可以在最后的可变参数之前。 这是一个方法,接受一个列表,并将所有附加参数添加到列表的末尾:

  public static <T> void addAll(List<T> list, T... arr) {
    for (T elt : arr) list.add(elt);
  }

每当声明可变参数时,可以将参数列表传递给数组,或直接显式传递数组。 因此,可以如下调用前面的方法:

  List<Integer> ints = new ArrayList<Integer>();
  Lists.addAll(ints, 1, 2);
  Lists.addAll(ints, new Integer[] { 3, 4 });
  assert ints.toString().equals("[1, 2, 3, 4]");

我们稍后会看到,当我们尝试创建一个包含泛型类型的数组时,我们总是会收到一个未经检查的警告。 由于可变参数总是创建一个数组,所以只有在参数没有泛型时才能 使用它们(见6.8节)。

在前面的例子中,泛型方法的类型参数被推断出来,但是也可以被明确给出,如下面的例子所示:

  List<Integer> ints = Lists.<Integer>toList();
  List<Object> objs = Lists.<Object>toList(1, "two");

显式参数通常不是必需的,但是在这里给出的例子中它们是有帮助的。 在第一个例子中,如果没有类型参数,那么 Sun 的编译器用来推断正确类型的类型推断算法的 信息就太少了。 它推断 toList 的参数是一个任意泛型类型的空数组,而不是一个空整型数组,这触发了前面描述的未经检查的警告。 (Eclipse 编译器使用不 同的推理算法,并在没有显式参数的情况下正确地编译相同的行。)在第二个示例中,没有类型参数,类型推理算法的信息太多,无法推断出正确的类型。 你可能会认为 Object 是唯一一个整数和字符串有共同的类型,但实际上它们都实现了 SerializableComparable 接口。 类型推断算法不能选择这三种中的哪一种是正确 的类型。

一般来说,下面的经验法则就足够了:在对通用方法的调用中,如果存在的话是一个或多个参数对应于一个类型参数,他们都有相同的类型,那么可以推断出类型参数; 如果没有对应于类型参数的参数,或者参数属于预期类型的不同子类型,则必须明确给出类型参数。

当一个类型参数传递给泛型方法调用时,它将以角度出现括号在左边,就像在方法声明中一样。Java 语法要求类型参数只能出现在使用虚线形式的方法调用中。 即使 方法 toList 在调用代码的同一个类中定义,我们也不能缩短它如下:

   List<Integer> ints = <Integer>toList(); // 编译报错

这是非法的,因为它会混淆解析器。

方法集合框架中的 Arrays.asListCollections.addAll 是类似于之前显示的 toListaddAll。 (这两个类都在 java.util 包中)asList 的集合框架版本不返回 ArrayList,而是返回由给定数组支持的专用列表类。 此外,其版本的 addAll 作用于一般集合,而不仅仅是列表。

《《《 下一节
《《《 返回首页