34

在浏览该EnumSet<E> of方法时,我看到了方法的多个重载实现of

public static <E extends Enum<E>> EnumSet<E> of(E e)

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2)

.
.

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)

然后是另一个重载方法varargs

public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
    EnumSet<E> result = noneOf(first.getDeclaringClass());
    result.add(first);
    for (E e : rest)
        result.add(e);
    return result;
}

当这个可变参数可以处理其他实现时,为什么这个方法会以这种方式重载?这有什么具体原因吗?

我已经阅读了相同的 Javadoc,但找不到任何令人信服的解释。

4

4 回答 4

29

Varargs 方法创建一个数组。

public static void foo(Object... args) {
  System.out.println(args.length);
}

这是有效的,因为隐式数组创建。EnumSet是一个设计得非常非常快的类,因此通过创建所有额外的重载,他们可以在前几个情况下跳过数组创建步骤。尤其如此,因为在许多情况下Enum没有那么多元素,如果有,则EnumSet可能不会包含所有元素。

Javadoc 用于EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)

创建一个最初包含指定元素的枚举集。存在此方法的重载以初始化具有一到五个元素的枚举集。提供了使用可变参数功能的第六个重载。此重载可用于创建最初包含任意数量元素的枚举集,但可能比不使用可​​变参数的重载运行得更慢。

于 2015-08-10T16:13:05.887 回答
8

varags 创建一个数组,也就是我们调用的时候

void x(int...x) {...}
..
x(1);

编译器将最后一行替换为:

x(new int[] {1});

如果我们有一个带有 1 个参数的重载方法,它就不会发生:

void x(int...x) {...}
void x(int x) {...}

然后编译器将选择第二种方法。

于 2015-08-10T16:15:03.073 回答
7

因为那个类是由 Josh Bloch 设计的,而且那个人知道事情是如何运作的。:) 除了创建数组,varargs 方法还包含循环,这是 JIT 优化代码的更多工作。

例如,如果我们查看具有五个参数的重载版本的实现:

result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);

我们注意到它是某种已经展开的循环,看起来像:

for (E e : Arrays.asList(e1, e2, e3, e4, e5)) {
   result.add(e);
}

此外,更短和更简单的方法比更长和更复杂的方法更有可能被内联。

于 2015-08-10T17:31:42.590 回答
6

javadoc

存在此方法的重载以初始化具有一到五个元素的枚举集。提供了使用可变参数功能的第六个重载。此重载可用于创建最初包含任意数量元素的枚举集,但可能比不使用可​​变参数的重载运行得更慢。

于 2015-08-10T16:13:14.540 回答