这其中的某些方面可能是未来证明的一种形式。
如果你发展了一个API,你需要注意方法签名将如何变化,所以如果我们有
public class API {
public static final <T> Set<T> of(T... elements) { ... }
}
我们可以说varargs已经足够好了...除了 varargs 强制分配对象数组,这虽然相当便宜,但实际上确实会影响性能。例如,请参阅此微基准标记,它显示切换到 varargs 形式时,无操作日志记录(即对数级别低于 loggable)的吞吐量损失 50%。
好吧,所以我们做了一些分析,并说最常见的情况是单例,所以我们决定重构...
public class API {
public static final <T> Set<T> of(T first) { ... }
public static final <T> Set<T> of(T first, T... others) { ... }
}
哎呀...这不是二进制兼容的...它是源代码兼容的,但不是二进制兼容的...为了保持二进制兼容性,我们需要保留以前的签名,例如
public class API {
public static final <T> Set<T> of(T first) { ... }
@Deprecated public static final <T> Set<T> of(T... elements) { ... }
public static final <T> Set<T> of(T first, T... others) { ... }
}
呸。。。IDE代码完成现在是一团糟...以及如何创建一组数组?(如果我使用列表,可能更相关)是模棱两可的...如果我们一开始就没有添加vararg就好了...API.of(new Object[0])
所以我认为他们所做的是添加足够的显式参数,以达到额外的堆栈大小满足vararg创建成本的地步,这可能是大约10个参数(至少基于Log4J2在将varargs添加到版本2 API时所做的测量)...但你这样做是为了基于证据的未来证明...
换句话说,我们可以欺骗所有我们没有证据需要专门实现的情况,只是跌倒在vararg变体上:
public class API {
private static final <T> Set<T> internalOf(T... elements) { ... }
public static final <T> Set<T> of(T first) { return internalOf(first); }
public static final <T> Set<T> of(T first, T second) { return internalOf(first, second); }
...
public static final <T> Set<T> of(T t1, T t2, T t3, T t4, T t5, T... rest) { ... }
}
然后,我们可以分析并查看现实世界的使用模式,如果我们看到高达4 arg形式和基准的重要使用情况,则表明存在合理的性能增益,那么在这一点上,在幕后,我们改变了方法impl,每个人都会赢......无需重新编译