Java 克隆如何比对象创建更具性能
我试图了解java中clone()方法下面发生了什么,我想知道如何比执行新调用更好Java 克隆如何比对象创建更具性能,java,performance,clone,cloneable,Java,Performance,Clone,Cloneable,我试图了解java中clone()方法下面发生了什么,我想知道如何比执行新调用更好 public class Person implements Cloneable { private String firstName; private int id; private String lastName; //constructors, getters and setters @Override protected Object clone()
public class Person implements Cloneable {
private String firstName;
private int id;
private String lastName;
//constructors, getters and setters
@Override
protected Object clone() throws CloneNotSupportedException {
Person p = (Person) super.clone();
return p;
}
}
这是我的克隆代码,我想知道下面发生了什么,以及新调用之间的区别
这是我的客户代码
Person p = new Person("John", 1, "Doe");
Person p2 = null;
try {
p2 = (Person) p.clone();
} catch (CloneNotSupportedException ex) {
Logger.getLogger(clientPrototype.class.getName()).log(Level.SEVERE, null, ex);
}
p2.setFirstName("Jesus");
System.out.println(p);
System.out.println(p2);
如果需要副本,请调用clone(),如果不需要,请调用构造函数。
标准克隆方法(java.lang.Object.clone())创建对象的浅层副本,而不调用构造函数。如果需要深度复制,则必须重写克隆方法
不要担心性能。
性能取决于克隆方法和构造函数的内容,而不是所使用的技术(新的或克隆的)本身
编辑:克隆和构造函数实际上并不是相互交替的,它们满足了不同的目的约阿希姆是对的。如果您需要复制使用克隆,如果您需要一个seprate对象(对于seprate人员),您应该使用
new
并创建一个新对象
“更多性能”是主观的,在这里可能不是正确的术语。克隆中发生的情况是底层对象是共享的,即它们对同一内存位置有两个单独的引用。因此,您可以有效地节省创建对象和内存。还记得深拷贝/浅拷贝吗 public void testPerformance(){
public void testPerformance(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
long start = System.currentTimeMillis();
for(int i = 0; i < 1000000; i++){
SimpleDateFormat localSdf = (SimpleDateFormat)sdf.clone();
}
System.out.println("Cloning : " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for(int i = 0; i < 1000000; i++){
Object localSdf = new SimpleDateFormat("yyyy-MM-dd");
}
System.out.println("Creating : " + (System.currentTimeMillis() - start) + " ms");
}
SimpleDataFormat sdf=新SimpleDataFormat(“yyyy-MM-dd”);
长启动=System.currentTimeMillis();
对于(int i=0;i<1000000;i++){
SimpleDataFormat localSdf=(SimpleDataFormat)sdf.clone();
}
System.out.println(“克隆:”+(System.currentTimeMillis()-start)+“ms”);
start=System.currentTimeMillis();
对于(int i=0;i<1000000;i++){
对象localSdf=新的SimpleDataFormat(“yyyy-MM-dd”);
}
System.out.println(“创建:”+(System.currentTimeMillis()-start)+“ms”);
}
克隆:302毫秒
创建:885毫秒我为类人
创建:
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%。我的要求是为一个类创建1000个对象。所有这些对象共享大多数公共属性。因此,我决定创建一个具有公共属性的基本对象,并克隆它和克隆的对象集对象特定属性。这会对性能产生什么影响?。我尝试了与上面相同的示例,使用了不同的方法,并没有发现太多稳定的性能差异。这是我的代码和结果
import java.util.*;
import java.util.stream.*;
import java.text.*;
public class Test{
public static void main(String[] args){
try{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
long start = System.currentTimeMillis();
SDFHolder holder = new SDFHolder();
holder.setSdf(sdf);
for(int i = 0; i < 1000000; i++){
SDFHolder locHolder = (SDFHolder)holder.clone();
}
System.out.println("Cloning : " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for(int i = 0; i < 100000000; i++){
SDFHolder locHolder = new SDFHolder();
locHolder.setSdf(sdf);
}
System.out.println("Creating : " + (System.currentTimeMillis() - start) + " ms");
} catch(Exception e){
e.printStackTrace();
}
}
}
class SDFHolder implements Cloneable {
private SimpleDateFormat sdf;
public void setSdf(SimpleDateFormat sdf){
this.sdf = sdf;
}
public SimpleDateFormat getSdf(){
return this.sdf;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
因此,我不认为这对性能有太大的影响,但根据我的要求提供了更简洁的代码。为什么您认为clone()比创建对象有更好的性能?那不是真的。首先使用
clone()
也是一个好主意。你会用什么来代替clone,还有,为什么不是真的clone有更好的性能呢?.clone()
(假设它下面使用Object.clone()
)它生成的对象与调用它的对象具有相同的运行时类,而如果使用new
,则在编译时将对正在创建的对象类进行硬编码,这可能与对象的确切运行时类不同(对象的类可以是指向它的变量的编译时类型的子类)。和往常一样,在谈论克隆时,要不惜一切代价避免它。它是一个不完整的特性,极易引入错误,极难正确实现。而且在继承的情况下更难维护正确的实现(高效Java对该主题有很好的理解)。有更安全、更好的方法来创建副本。例如,通过在类中引入副本构造函数。因此,您所说的新建对象和克隆对象具有相同的影响?不,影响取决于构造函数和克隆方法的内容。如果类只有少数成员,则使用简单的默认构造函数和不重写克隆(),其影响可能类似。
我的建议是,仅当您需要现有对象的副本时才使用克隆。克隆和构造函数并不是相互替代的,它们满足不同的目的。因此,如果我想要克隆现有对象,它会比使用与我的o相同的值新建新对象具有更高的性能吗对象?通常无法回答。如果您的类只有原语,而您没有重写clone(),并且您的构造函数处理一些工作,则clone()是可能
更快。但是这个讨论有点没用,因为你应该使用你需要的技术,而不是最快的技术或可能最快的
技术。构建和克隆是不同的概念,你应该选择适合你需要的技术。嗯,好吧,但是让我们假设我想要这个ca中最快的se,克隆会让它更快吗?你能给我解释一下你说的关于两个对象在内存中有相同的内存位置的事情吗?如果我编辑一个,为什么另一个没有改变?这不是两个引用有两个独立的内存位置吗?这里有一个合理的解释:用户想知道引擎盖下发生了什么克隆函数不仅仅是性能。它不是关于对象克隆与构造函数性能的关系,它更多的是关于SimpleDataFormat
,因为这个特定的构造函数非常重。我建议让它的静态实例重新使用。@kairius static有一大堆憎恨者,他们把它与全局状态的罪恶混为一谈,因为几乎任何上下文都可能是可重入的。Final是我的朋友。我不是在质疑编程实践,我只是说SimpleDateFormat构造函数非常重,而且很慢
C:\Users\thangaraj.s\Desktop>java Test
Cloning : 15 ms
Creating : 0 ms
C:\Users\thangaraj.s\Desktop>java Test
Cloning : 16 ms
Creating : 0 ms
C:\Users\thangaraj.s\Desktop>java Test
Cloning : 0 ms
Creating : 15 ms
C:\Users\thangaraj.s\Desktop>java Test
Cloning : 0 ms
Creating : 16 ms
C:\Users\thangaraj.s\Desktop>java Test
Cloning : 16 ms
Creating : 0 ms