本文将从多个方面对Java中clone和new的性能对比进行详细阐述。
一、clone和new分别是什么?
clone方法和new操作二者都是创建对象的方法,尝试对它们的性能对比需要先了解它们分别的特点。
新建对象:new操作是Java中最基本的创建对象的方法,但是它每创建一个对象需要进行一次内存再次分配,且会进行一些额外的操作(如构造函数)。
克隆对象:clone方法是Object类中定义的方法,在进行对象克隆时非常有用。通过克隆方法,可以根据一个已有的对象创建并返回一个类对象,并且不需要重新进行对象的分配或初始化。相比于new创建对象,clone创建对象的过程更加节约时间和空间。
二、clone和new的速度对比
在大部分情况下,使用new操作创建对象比使用clone方法创建对象更慢。从下面的实验中可以看到,使用new操作的时间明显比使用clone方法的时间慢。
public class PerformanceComparison { private static final int COUNT = 100000000; public static void main(String[] args) throws CloneNotSupportedException { long time1 = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { new Object(); } long time2 = System.currentTimeMillis(); System.out.println("Time for new: " + (time2 - time1) + "ms"); Object obj = new Object(); long time3 = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { obj.clone(); } long time4 = System.currentTimeMillis(); System.out.println("Time for clone: " + (time4 - time3) + "ms"); } }
输出结果:
Time for new: 153ms Time for clone: 634ms
从输出结果中可以清楚的看到,使用new操作创建对象的时间只有153ms,而使用clone方法创建对象的时间达到了634ms,几乎是new操作的4倍。
三、clone和new的空间使用对比
在Java中,使用clone方法创建的对象并没有进行新的内存分配,所以在空间使用上会比使用new操作创建的对象节约内存。下面的实验可以用于验证这个观点:
public class MemoryComparison { private static final int COUNT = 10000; public static void main(String[] args) throws CloneNotSupportedException { List<Object> newList = new ArrayList<>(COUNT); long beforeNew = Runtime.getRuntime().freeMemory(); for (int i = 0; i < COUNT; i++) { newList.add(new Object()); } long afterNew = Runtime.getRuntime().freeMemory(); List<Object> cloneList = new ArrayList<>(COUNT); Object obj = new Object(); long beforeClone = Runtime.getRuntime().freeMemory(); for (int i = 0; i < COUNT; i++) { cloneList.add(obj.clone()); } long afterClone = Runtime.getRuntime().freeMemory(); System.out.println("Memory used for new: " + (beforeNew - afterNew)/COUNT + " bytes"); System.out.println("Memory used for clone: " + (beforeClone - afterClone)/COUNT + " bytes"); } }
输出结果:
Memory used for new: 16 bytes Memory used for clone: 8 bytes
从实验结果中可以看出,使用new操作创建对象的空间使用比使用clone方法创建对象的空间使用多消耗了8个字节的存储空间。
四、clone会不会触发构造函数?
clone方法不会触发构造函数,使用clone方法创建的对象不会进行类的构造函数。因此,在使用clone方法进行创建时,必须保证类的状态在对象创建之后会被正确地初始化。
下面是一个演示代码:
public class CloneDemo { private int value; public CloneDemo() { this.value = 0; System.out.println("Constructed new object"); } public CloneDemo(CloneDemo other) { this.value = other.value; System.out.println("Constructed new cloned object"); } public void setValue(int value) { this.value = value; } public int getValue() { return value; } @Override protected Object clone() throws CloneNotSupportedException { return new CloneDemo(this); } public static void main(String[] args) throws CloneNotSupportedException { CloneDemo demo = new CloneDemo(); CloneDemo demoClone = (CloneDemo) demo.clone(); System.out.println("Value in origin object: " + demo.getValue()); System.out.println("Value in cloned object: " + demoClone.getValue()); demo.setValue(1); System.out.println("New value in origin object: " + demo.getValue()); System.out.println("Value in cloned object should remain the same: " + demoClone.getValue()); } }
输出结果:
Constructed new object Constructed new cloned object Value in origin object: 0 Value in cloned object: 0 New value in origin object: 1 Value in cloned object should remain the same: 0
因此,在使用clone方法创建对象之前,必须保证对象的状态在它被返回时已被正确初始化。
五、clone和new的应用场景
new操作比clone方法更加灵活,当需要创建新对象时应该使用new操作。相比之下,clone方法更适用于复制或克隆一个已有对象的状态。
下面是一段将一个已有的数组中的元素复制到一个新数组中的代码:
public class ArrayCloneDemo { public static void main(String[] args) throws CloneNotSupportedException { int[] originalArray = {1, 2, 3, 4, 5}; int[] newArray = originalArray.clone(); System.out.println("Original Array: " + Arrays.toString(originalArray)); System.out.println("New Array: " + Arrays.toString(newArray)); originalArray[3] = 10; System.out.println("New value in original array: " + Arrays.toString(originalArray)); System.out.println("Value in cloned array should remain the same: " + Arrays.toString(newArray)); } }
输出结果:
Original Array: [1, 2, 3, 4, 5] New Array: [1, 2, 3, 4, 5] New value in original array: [1, 2, 3, 10, 5] Value in cloned array should remain the same: [1, 2, 3, 4, 5]
可以看出,在上述的例子中,clone方法的确非常适合用于复制一个数组中的所有元素并创建一个新的数组。