.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) );
}
4 ответа
Обновление с использованием JMH
Используя JMH, я получаю аналогичные результаты, за исключением того, что clone
кажется немного лучше.
Оригинальный пост
Я провел быстрый тест на производительность: clone
, System.arrayCopy
а также Arrays.copyOf
имеют очень похожую производительность (JDK 1.7.06, сервер 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];
}
Также обратите внимание на безопасность использования "clone ()". Класс известных атак использует классы, которые переопределяют методы "clone ()" объектов вредоносным кодом. Например, CVE-2012-0507 (атака "Flashback" в Mac OS) была решена путем замены вызова ".clone ()" на вызов ".copyOf".
Дополнительное обсуждение устаревшей функции "clone ()" можно найти в Stackru здесь: клонирование объектов без реализации клонируемого интерфейса
Я написал простую программу, чтобы проверить разницу.
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
Для массива строк 1000000
и для количества итераций 10000
Time Required for Copy of: 32825
Time Required for Clone: 30138
copy of
занимает больше времени, чем clone
С точки зрения изменчивости, они будут предоставлять точно такую же - мелкую копию данных.