为什么 EnumSet 有很多重载的 "of" 方法?
Why does EnumSet have many overloaded "of" methods?
在使用 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,但找不到任何令人信服的解释。
Varargs 方法创建一个数组。
public static void foo(Object... args) {
System.out.println(args.length);
}
这是可行的,因为隐式数组创建。 EnumSet
是一个 class 设计得非常非常快,因此通过创建所有额外的重载,他们可以 在前几种情况下跳过数组创建步骤 。尤其如此,因为在许多情况下 Enum
没有那么多元素,如果有,EnumSet
可能不会包含所有元素。
Javadoc for EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
:
Creates an enum set initially containing the specified elements. Overloadings of this method exist to initialize an enum set with one through five elements. A sixth overloading is provided that uses the varargs feature. This overloading may be used to create an enum set initially containing an arbitrary number of elements, but is likely to run slower than the overloadings that do not use varargs.
来自javadoc:
Overloadings of this method exist to initialize an enum set with
one through five elements. A sixth overloading is provided that
uses the varargs feature. This overloading may be used to create
an enum set initially containing an arbitrary number of elements, but
is likely to run slower than the overloadings that do not use varargs.
varags 创建一个数组,也就是当我们调用
void x(int...x) {...}
..
x(1);
编译器将最后一行替换为:
x(new int[] {1});
如果我们有一个带有 1 个参数的重载方法,则不会发生这种情况:
void x(int...x) {...}
void x(int x) {...}
然后编译器会选择第二种方法。
因为 class 是由 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);
}
此外,较短和较简单的方法比较长和较复杂的方法更有可能被内联。
在使用 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,但找不到任何令人信服的解释。
Varargs 方法创建一个数组。
public static void foo(Object... args) {
System.out.println(args.length);
}
这是可行的,因为隐式数组创建。 EnumSet
是一个 class 设计得非常非常快,因此通过创建所有额外的重载,他们可以 在前几种情况下跳过数组创建步骤 。尤其如此,因为在许多情况下 Enum
没有那么多元素,如果有,EnumSet
可能不会包含所有元素。
Javadoc for EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
:
Creates an enum set initially containing the specified elements. Overloadings of this method exist to initialize an enum set with one through five elements. A sixth overloading is provided that uses the varargs feature. This overloading may be used to create an enum set initially containing an arbitrary number of elements, but is likely to run slower than the overloadings that do not use varargs.
来自javadoc:
Overloadings of this method exist to initialize an enum set with one through five elements. A sixth overloading is provided that uses the varargs feature. This overloading may be used to create an enum set initially containing an arbitrary number of elements, but is likely to run slower than the overloadings that do not use varargs.
varags 创建一个数组,也就是当我们调用
void x(int...x) {...}
..
x(1);
编译器将最后一行替换为:
x(new int[] {1});
如果我们有一个带有 1 个参数的重载方法,则不会发生这种情况:
void x(int...x) {...}
void x(int x) {...}
然后编译器会选择第二种方法。
因为 class 是由 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);
}
此外,较短和较简单的方法比较长和较复杂的方法更有可能被内联。