代码之家  ›  专栏  ›  技术社区  ›  jjnguy Julien Chastang

为什么guava的不可变列表中有这么多重载的()方法?

  •  38
  • jjnguy Julien Chastang  · 技术社区  · 14 年前

    我只是在看番石榴 ImmutableList 我注意到 of() 方法被重载12次。

    在我看来,他们所需要的只是:

    static <E> ImmutableList<E> of();
    static <E> ImmutableList<E> of(E element); // not even necessary
    static <E> ImmutableList<E> of(E... elements);
    

    为什么会有这么多相似的变化?

    3 回复  |  直到 14 年前
        1
  •  39
  •   ColinD    13 年前

    varargs和generics不能很好地结合在一起。varargs方法可能导致带有泛型参数的警告,并且重载会阻止该警告,除非在极少数情况下,您希望使用 of() .

    消息来源中的评论说:

    这些最多十一个。在那之后,您只需要得到varargs表单,以及任何可能伴随它的警告。:(

    请注意Java 7的 @SafeVarargs 特别添加注释是为了消除对这类事情的需要。单人间 of(E...) 方法注释为 @SafeVarargs 无法使用,并且不会用泛型参数发出警告。

        2
  •  13
  •   Rinke    12 年前

    还有一个性能原因。每次调用varargs方法都会导致数组分配和初始化。如果您以某种方式确定,例如95%的调用包含3个或更少的参数,只有5%包含4个或更多参数,那么这样的重载

    public static <E> ImmutableList<E> of();
    public static <E> ImmutableList<E> of( E e );
    public static <E> ImmutableList<E> of( E e1, E e2 );
    public static <E> ImmutableList<E> of( E e1, E e2, E e3 );
    public static <E> ImmutableList<E> of( E e1, E e2, E e3, E... es );
    

    在95%的案例中,性能得到了很好的提升。换言之,案件的平均表现会上升。

        3
  •  4
  •   Andrew McNamee    12 年前

    除此之外,还有一个微妙的运行时性能优势(除了避免数组分配之外),即零arg和单arg重载返回为表示空实例列表和单实例列表(分别)而优化的实现。

    如果我们没有为这些单独的方法重载,并且只包含一个基于varargs的方法,那么该方法将如下所示:

    public static <E> ImmutableList<E> of(E... es) {
        switch (es.length) {
          case 0:
            return emptyImmutableList();
          case 1:
            return singletonImmutableList(es[0]);
          default:
            return defaultImmutableList(es);
        }
    }
    

    对于大多数调用来说,switch case的性能(或者if-else检查)不会很差,但是它仍然是不必要的,因为每个优化都可以有方法重载,并且编译器总是知道要调用哪个重载。客户机代码没有负担,所以很容易获胜。