在浏览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;
}
当这个varargs可以处理其他实现时,为什么这个方法会以这种方式重载?这有什么具体原因吗?
我经历过同样的Javadoc,但我找不到任何令人信服的解释。
答案 0 :(得分:30)
public static void foo(Object... args) {
System.out.println(args.length);
}
这是有效的,因为隐式数组创建。 EnumSet
是一个非常非常快的类,因此通过创建所有额外的重载,他们可以在前几种情况下跳过数组创建步骤。这尤其正确,因为在许多情况下Enum
没有那么多元素,如果有,EnumSet
可能不包含所有元素。
Javadoc for EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
:
创建最初包含指定元素的枚举集。存在此方法的过载以初始化具有一到五个元素的枚举集。提供了使用varargs功能的第六次重载。这个重载可以用来创建一个最初包含任意数量元素的枚举集,但是可能比不使用varargs的重载运行得慢。
答案 1 :(得分:8)
varags创建一个数组,就在我们调用
时void x(int...x) {...}
..
x(1);
编译器用以下代码替换最后一行:
x(new int[] {1});
如果我们使用1 arg:
的重载方法,则不会发生这种情况void x(int...x) {...}
void x(int x) {...}
然后编译器将选择第二种方法。
答案 2 :(得分:7)
因为那个班级是由Josh Bloch设计的,那个人知道事情是如何运作的。 :)除了创建数组之外,varargs方法还包含循环,这对JIT来说更有效,可以优化代码。
例如,如果我们查看带有五个参数的重载版本的实现:
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);
我们注意到它是某种已经unrolled loop的样子:
for (E e : Arrays.asList(e1, e2, e3, e4, e5)) {
result.add(e);
}
此外,更短更简单的方法更有可能被内联,而不是更长和更复杂的方法。
答案 3 :(得分:6)
来自javadoc:
此方法的过载用于初始化枚举集 一至五个要素。提供了第六次重载 使用varargs功能。这种重载可用于创建 枚举集最初包含任意数量的元素,但是 可能比不使用varargs的过载运行得慢。