9

在我的项目中,有一些“原型”工厂通过克隆最终的私有实例来创建实例。

这些工厂的作者说,这种模式提供了比调用“新”运算符更好的性能。

使用谷歌获得一些线索,我没有发现任何相关的东西。这是在未知项目的 javdoc中找到的一小段摘录

可悲的是,clone() 比调用 new 慢得多。然而,它比调用 java.lang.Class.newInstance() 快得多,并且比滚动我们自己的“克隆”方法要快一些。

对我来说,它看起来像是 java 1.1 时代的一个古老的最佳实践。有人知道更多吗?这是将它与“现代”jvm 一起使用的好习惯吗?

4

6 回答 6

24

当然,这种做法已经完全过时了。从那时起,Java 虚拟机有了很大的改进。对象创建非常便宜。另一个相关的实践,对象池,也已经过时了,因为对象创建和清理的成本现在要高效得多。在某些情况下它可能有用(Jon Skeet 在这里给出了一些很好的例子),但它绝不应该是这样的基础框架库的一部分。

我建议找一些新的库和/或一个新的项目来工作;-)

查看此类文章Java Urban Performance Legends以获得更多见解。

于 2010-03-11T17:50:14.970 回答
2

哎呀。这是我听过的最糟糕的想法之一。

不要做奇怪的事情。即使您已经测量并看到了一些明显的改进(在这种情况下,这种情况的可能性为零),在做之前要考虑很长时间。谁知道它会在下一个 JVM 中修复。然后你会留下一些奇怪的代码,这些代码性能更差,难以阅读,并且因此出现一些错误。

我的意思是,开发JVM的人不是白痴!使用new

我认为你应该摆脱那段奇怪的代码。

于 2010-03-11T17:52:24.873 回答
2

正如其他人所说,这是一种过时的做法。这是一种过时的模式,不幸的是,较新的 JVM 会给代码增加更多的臃肿,而不会提高性能。

我希望我还有代码所以我可以分享,但不久前我对这种模式与使用“新”操作符进行了简单的性能测试,我发现使用“新”操作符在最坏的情况下至少与这种模式,充其量是更快,更高效。可能有一些边缘情况我的测试没有涵盖这仍然是一种有效的方法,但总的来说我会说避免这种模式。

不过,另一个注意事项是,如果它存在于现有代码库中,我建议您不要太担心这一点。但我也不会为你的项目的更多部分编写新代码来扩展这种模式,除非不这样做会损害你的代码库的清晰度和一致性——此时你应该评估它在从长远来看,从您的项目中重构此代码。我所说的“智能”是指,从您的项目中重构此代码是否会在将来节省开发和调试时间> 重构此代码所需的时间。

于 2010-03-11T18:05:31.853 回答
1

不。

哦,我需要更多字符来回答。因此,让我扩展并说,除非存在问题,否则这种微优化是不合适的,如果存在问题,那么您应该能够衡量它是否会使事情变得更好。

于 2010-03-11T17:51:24.043 回答
1

我为 class 创建了简单的基准Person。我正在使用最新的 OpenJDK 8:

public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

并得到以下结果:

Benchmark             Mode  Cnt     Score       Error   Units

MyBenchmark.viaClone  avgt   10     10.041 ±    0.059   ns/op
MyBenchmark.viaNew    avgt   10      7.617 ±    0.113   ns/op

这个简单的基准测试表明,实例化新对象并从源对象设置相应的属性比克隆它所花费的时间少 25%。

于 2017-07-13T07:47:14.137 回答
1

我使用 DecimalFormat (OpenJDK 8/Windows/JMH 1.19) 的测试显示完全相反的图像:

Benchmark               Mode  Cnt     Score     Error  Units
Format.everyTimeCreate  avgt   10  9326.967 ± 199.511  us/op
Format.useClone         avgt   10  5102.397 ±  72.993  us/op
Format.useGlobalWithTL  avgt   10  4605.604 ±  59.000  us/op

看起来回答什么表现更好并不是那么简单。

于 2017-10-18T20:27:23.413 回答