System.arraycopy() > clone() > Arrays.copyof() > for()
理论分析
前三种的复制方式都是相似的他们都是属于浅拷贝(基础类型的数据拷贝值,引用类型的数据拷贝引用),后面的用的是深拷贝,对于引用类型的数据来说相当于是直接建造了一个一模一样的新房屋。
@HotSpotIntrinsicCandidate注解的作用:JDK的Object类源码中,被@HotSpotIntrinsicCandidate标注的方法,在HotSpot中都有一套高效的实现,该高效实现基于CPU指令,运行时,HotSpot维护的高效实现会替代JDK的源码实现,从而获得更高的效率。
System.arraycopy() 是本地方法,也就是说是用C++写的,所以其效率比非native方法更高。它有@HotSpotIntrinsicCandidate注解,这个注解可以帮助他跳过JNI阶段进一步提高他的执行效率。这也是System.arraycopy()速度冠绝群雄的原因。
Object.clone()也是native方法,也有@HotSpotIntrinsicCandidate注解,但是从他的源码注解中可以看到It indicates that an annotated method may be (but is not guaranteed to be) intrinsified by the HotSpot VM它并没有被手工写在JVM里面,所以它不得不走JNI的路子,所以它就成了2哥。
Arrays.copyof():而且可以很明显的看到里面本质是调用了大哥 System.arraycopy()来实现的,并且他也不是本地方法,按理说他的效率是这三个最低的。
性能测试代码
@Test
public void test3(){
//伪造数据数组的长度
final int ArrayLength = 5000000;
final int count = 50;
Long[][] baseCostArrays = new Long[count][4];
Long[][] refCostArrays = new Long[count][4];
for (int i = 0; i < count; i++) {
baseCostArrays[i] = testBaseCopy(ArrayLength,i);
refCostArrays[i] = testRefCopy(ArrayLength,i);
}
//性能综合分析
System.out.println("数组数据类型long、String两种,长度为:"+ArrayLength+",循环测试测试次数为:"+count);
Long baseSystem = 0l;
Long baseClone = 0l;
Long baseArrays = 0l;
Long baseFor = 0l;
Long refSystem = 0l;
Long refClone = 0l;
Long refArrays = 0l;
Long refFor = 0l;
for (int i = 0; i <count; i++) {
baseSystem = baseSystem+baseCostArrays[i][0];
baseClone = baseClone+baseCostArrays[i][1];
baseArrays = baseArrays+baseCostArrays[i][2];
baseFor = baseFor+baseCostArrays[i][3];
refSystem = refSystem+refCostArrays[i][0];
refClone = refClone+refCostArrays[i][1];
refArrays = refArrays+refCostArrays[i][2];
refFor = refFor+refCostArrays[i][3];
}
System.out.println("~~~~~~~~~~~~~~数据性能分析~~~~~~~~~~~~~~~~~");
System.out.println("基础类型数据:");
System.out.println("System: _total:"+baseSystem+" _average:"+(baseSystem*1.0/count));
System.out.println("Clone: _total:"+baseClone+" _average:"+(baseClone*1.0/count));
System.out.println("Arrays: _total:"+baseArrays+" _average:"+(baseArrays*1.0/count));
System.out.println("For: _total:"+baseFor+" _average:"+(baseFor*1.0/count));
System.out.println("引用类型数据:");
System.out.println("System: _total:"+refSystem+" _average:"+(refSystem*1.0/count));
System.out.println("Clone: _total:"+refClone+" _average:"+(refClone*1.0/count));
System.out.println("Arrays: _total:"+refArrays+" _average:"+(refArrays*1.0/count));
System.out.println("For: _total:"+refFor+" _average:"+(refFor*1.0/count));
}
private Long[] testBaseCopy(int ArrayLength,int flag){
System.out.println("~~进行的是基础类型数组的第"+(flag+1)+"次复制测验~~");
Long costTimes[] = new Long[4];
//测试System形式的拷贝
float[] floats1 = new float[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
floats1[i] = 2342266L;
}
Long beginTime = new Date().getTime();
float[] systemCopyArrays = new float[floats1.length];
System.arraycopy(floats1,0,systemCopyArrays,0,floats1.length);
costTimes[0]=performanceUtils("System.arraycopy",beginTime);
//测试clone形式的拷贝
float[] floats2 = new float[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
floats2[i] = 2362566L;
}
beginTime = new Date().getTime();
float[] cloneCopyArrays = floats2.clone();
costTimes[1]=performanceUtils("clone()",beginTime);
//测试Arrays
float[] floats3 = new float[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
floats3[i] = 2342546L;
}
beginTime = new Date().getTime();
float[] arraysCopyArrays = Arrays.copyOf(floats3,floats3.length);
costTimes[2]=performanceUtils("Arrays.copyOf",beginTime);
//测试for
float[] floats4 = new float[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
floats4[i] = 2343566L;
}
beginTime = new Date().getTime();
float[] forCopyArrays = new float[floats4.length];
for (int i = 0; i < forCopyArrays.length; i++) {
forCopyArrays[i] = floats4[i];
}
costTimes[3]=performanceUtils("for",beginTime);
return costTimes;
}
private Long[] testRefCopy(int ArrayLength,int flag){
System.out.println("~~进行的是引用类型数组的"+(flag+1)+"复制测验~~");
Long costTimes[] = new Long[4];
Long beginTime = new Date().getTime();
//测试System形式的拷贝
String[] strings1 = new String[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
strings1[i] = new String("fasaadf");
}
beginTime = new Date().getTime();
String [] systemCopyArrays = new String[strings1.length];
System.arraycopy(strings1,0,systemCopyArrays,0,strings1.length);
costTimes[0] = performanceUtils("System.arraycopy",beginTime);
//测试clone形式的拷贝
String[] strings2 = new String[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
strings2[i] = new String("fasddf");
}
beginTime = new Date().getTime();
String[] cloneCopyArrays = strings2.clone();
costTimes[1]=performanceUtils("clone()",beginTime);
//测试Arrays
String[] strings3 = new String[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
strings3[i] = new String("fassuiouoioidf");
}
beginTime = new Date().getTime();
String[] arraysCopyArrays = Arrays.copyOf(strings3,strings3.length);
costTimes[2]=performanceUtils("Arrays.copyOf",beginTime);
//测试for
String[] strings4 = new String[ArrayLength];
for (int i = 0; i <ArrayLength; i++) {
strings4[i] = new String("fasdfdf");
}
beginTime = new Date().getTime();
String[] forCopyArrays = new String[strings4.length];
for (int i = 0; i < forCopyArrays.length; i++) {
forCopyArrays[i] = strings4[i];
}
costTimes[3]=performanceUtils("for",beginTime);
return costTimes;
}
private Long performanceUtils(String Name,Long beginTime){
Long duringTime = new Date().getTime()-beginTime;
System.out.println(Name+"类型操作耗时:"+duringTime+"毫秒");
return duringTime;
}
上面的测试结果我们可以看到他们之间的差别并不是有很大,并且Arrys的调用往往有更高的执行效率,对于这个问题我也比较疑问,不知道其中的原因,希望清楚的大佬可以留言指教一下。使用jdk15也是同样的执行效果