.clone() или Arrays.copyOf()?
В попытке уменьшить изменчивость, следует ли использовать
public void setValues(String[] newVals) {
this.vals = ( newVals == null ? null : newVals.clone() );
}
или
public void setValues(String[] newVals) {
this.vals = ( newVals == null ? null : Arrays.copyOf(newVals, newVals.length) );
}
Ответы
Ответ 1
Обновление с помощью jmh
Используя jmh, я получаю аналогичные результаты, за исключением того, что clone
кажется немного лучше.
Оригинальное сообщение
Я быстро проверил производительность: clone
, System.arrayCopy
и Arrays.copyOf
имеют очень похожую производительность (jdk 1.7.06, server vm).
Подробнее (в мс), после JIT:
клон: 68
arrayCopy: 68
Arrays.copyOf: 68
Тестовый код:
public static void main(String[] args) throws InterruptedException,
IOException {
int sum = 0;
int[] warmup = new int[1];
warmup[0] = 1;
for (int i = 0; i < 15000; i++) { // triggers JIT
sum += copyClone(warmup);
sum += copyArrayCopy(warmup);
sum += copyCopyOf(warmup);
}
int count = 10_000_000;
int[] array = new int[count];
for (int i = 0; i < count; i++) {
array[i] = i;
}
// additional warmup for main
for (int i = 0; i < 10; i++) {
sum += copyArrayCopy(array);
}
System.gc();
// copyClone
long start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyClone(array);
}
long end = System.nanoTime();
System.out.println("clone: " + (end - start) / 1000000);
System.gc();
// copyArrayCopy
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyArrayCopy(array);
}
end = System.nanoTime();
System.out.println("arrayCopy: " + (end - start) / 1000000);
System.gc();
// copyCopyOf
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyCopyOf(array);
}
end = System.nanoTime();
System.out.println("Arrays.copyOf: " + (end - start) / 1000000);
// sum
System.out.println(sum);
}
private static int copyClone(int[] array) {
int[] copy = array.clone();
return copy[copy.length - 1];
}
private static int copyArrayCopy(int[] array) {
int[] copy = new int[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy[copy.length - 1];
}
private static int copyCopyOf(int[] array) {
int[] copy = Arrays.copyOf(array, array.length);
return copy[copy.length - 1];
}
Ответ 2
Я написал простую программу для проверки разницы.
public static void main(String[] args) throws IOException, InterruptedException,
PrinterException
{
//Verify array remains immutable.
String[] str = {"a","b","c"};
String[] strings = str.clone();
//change returned array
strings[2]= "d";
System.out.println(Arrays.toString(str));
System.out.println(Arrays.toString(strings));
String[] stringsCopy = Arrays.copyOf(str, str.length);
stringsCopy[2]= "d";
System.out.println(Arrays.toString(str));
System.out.println(Arrays.toString(stringsCopy));
//peformance
long before = System.currentTimeMillis();
for(int i=0;i<Integer.MAX_VALUE;i++)
{
str.clone();
}
System.out.println("Time Required for Clone: "+ (System.currentTimeMillis()-before));
//peformance
long beforeCopy = System.currentTimeMillis();
for(int i=0;i<Integer.MAX_VALUE;i++)
{
Arrays.copyOf(str, str.length);
}
System.out.println("Time Required for Copy of: "+ (System.currentTimeMillis()-beforeCopy));
}
И он выводит
[a, b, c]
[a, b, d]
[a, b, c]
[a, b, d]
Time Required for Clone: 26288
Time Required for Copy of: 25413
Итак, если вы видите, что в обоих случаях String[]
неизменен, а производительность почти такая же, то Arrays.copyOf() немного быстрее на моей машине.
Обновление
Я изменил программу для создания большого массива [100 строк], а не небольшого массива.
String[] str = new String[100];
for(int i= 0; i<str.length;i++)
{
str[i]= Integer.toString(i);
}
И переместил метод copy of
до метода clone
. Ниже приведены результаты.
Time Required for Copy of: 415095
Time Required for Clone: 428501
Которые снова более похожи. Please do not ask me to run the test again as it takes a while
: (
Обновление 2
Для массива String 1000000
и для количества итераций 10000
Time Required for Copy of: 32825
Time Required for Clone: 30138
copy of
занимает больше времени, чем clone
Ответ 3
Также обратите внимание на безопасность использования "clone()" . Класс хорошо известных атак использует классы, которые переопределяют методы "clone()" объектов со вредоносным кодом. Например, CVE-2012-0507 (атака "Flashback" на Mac OS) была решена в основном заменой вызова ".clone()" с вызовом ".copyOf".
Дополнительное обсуждение устаревших "clone()" можно найти здесь: клонирование объектов без реализации клонированного интерфейса
Ответ 4
В терминах изменчивости они будут предоставлять точно такую же - мелкую копию данных.