【问题标题】:Equivalient method overload why necessary?等效方法重载为什么需要?
【发布时间】:2014-02-28 13:45:12
【问题描述】:

我浏览了一些谷歌制作的JAVA代码,找到了ImmutableSet:http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableSet.html

他们用其他几种方式实现了 of() 方法:

public static <E> ImmutableSet<E> of(E e1, E e2);
public static <E> ImmutableSet<E> of(E e1, E e2, E e3);
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4);
public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5);
public static <E> ImmutableSet<E> of(E... elements);

我检查了这里的实现:https://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/collect/ImmutableSet.java

有一个带有以下签名的 create 方法:

private static <E> ImmutableSet<E> create(E... elements)

包装了

private static <E> ImmutableSet<E> create(Iterable<? extends E> iterable, int count);

方法。公共方法只是将参数传递给 create(E... elements) 签名方法,该方法最终调用另一个 create 方法。

我猜想,由于我们有 of(E... elements) 方法,所以没有必要公开具有固定参数数量的方法。

我的问题是,他们为什么要这样做?表现?还是一种模式?

谢谢。

【问题讨论】:

  • 旁注:如果您使用的是旧的 Google 收藏库,请不要使用,它不再受支持。使用新的闪亮的Google Guava,它取代了谷歌收藏(并且正在积极开发)。

标签: java performance theory


【解决方案1】:

它实际上与性能无关:所有方法都委托给同一个创建方法,无论如何都需要一个数组。

我的猜测是它与警告有关。考虑以下最小的 sn-p:

import java.util.List;

class ImmutableSet<T>
{
}
public class ParametersTest
{
    public static void main(String[] args)
    {
        List<String> list0 = null;
        List<String> list1 = null;
        of(list0, list1);
    }

    @SuppressWarnings("unchecked")
    public static <E> ImmutableSet<E> of(E e1, E e2) {
        return create(e1, e2);
    }

    public static <E> ImmutableSet<E> of(E... elements) {
        return create(elements);
    }

    private static <E> ImmutableSet<E> create(E... elements) 
    {
        return null;
    }

}

在 main 方法中对 of 的调用很好:它与 of 方法的 2-args-version 匹配。现在注释掉of-方法的2-args-version。然后调用还是可以的,但是会直接调用 varags 版本。这将导致创建一个通用数组,并引发警告。 (显然,此警告在 2-args 版本中被抑制)。

总而言之,我假设这是为了避免对想要使用多个泛型对象调用 of 方法的库客户发出警告。

幸运的是,未来不再需要这样的事情,感谢http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html

【讨论】:

  • 你是对的。大约一分钟前我发现了这个:stackoverflow.com/questions/4314883/… 所以我的问题实际上是重复,很抱歉,但是这个答案表明这种方式是由于警告而被转发的。
【解决方案2】:

他们这样做是为了以更有效的方式管理内存。如果您有一个包含少量项目的不可变集合,最好显式地固定集合的大小。否则,Java 将创建一个更大的集合。例如:一个 HashSet,除非另有说明,否则初始大小为 12 个条目。

【讨论】:

  • AFAIK,不可变集合的大小将始终根据插入的元素数量适当调整,无论您使用什么方法来实例化它。并且默认 HashSet 的大小为 16(以允许在从 hashCode 计算正确的存储桶时使用二进制 AND 而不是 mod 操作的技巧)。或者最近有什么变化?
  • 由于所有提到的of 重载都调用了完全相同的create 方法,我看不出他们怎么可能做任何不同的事情(比如固定大小)。
  • 你是对的。我错过了它最终委托给独特方法的部分。
【解决方案3】:

性能。为了调用 E... 版本的方法,调用者必须分配一个新数组。调用者只需将参数压入堆栈即可调用其他方法。

【讨论】:

  • 但是他们仍然调用create的可变参数版本,所以无论哪种方式都会创建一个数组,不是吗?
  • 如果代码是 JIT 编译的,并且编译器很好,它可能会传递寄存器中的部分或全部参数,假设该方法不是递归的。
  • @AlexD 我很确定 JIT 编译器不能用可变参数方法做到这一点。
  • @sepp2k,如果编译器很好,没有理由不这样做。在任何给定的调用站点,传递的参数数量是一个已知的常数。调用站点专业化——一个非常强大的优化,可以使很多程序更快。给定的 JVM 是否真的进行了这种优化是另一个问题,我不知道答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-23
  • 2021-12-02
  • 1970-01-01
  • 2020-09-02
  • 2010-11-02
  • 1970-01-01
  • 2012-11-23
相关资源
最近更新 更多