Como copiar uma matriz em Java
1. Overview
Neste artigo rápido, discutiremos diferentes métodos de cópia de matriz em Java. A cópia da matriz pode parecer uma tarefa trivial, mas pode causar resultados inesperados e comportamentos do programa se não for feita com cuidado.
2. A classeSystem
Vamos começar com a biblioteca Java principal -System.arrayCopy(); isso copia um array de um array de origem para um array de destino, iniciando a ação de cópia da posição de origem para a posição de destino até o comprimento especificado.
O número de elementos copiados para a matriz de destino é igual ao comprimento especificado. Ele fornece uma maneira fácil de copiar uma sub-sequência de uma matriz para outra.
Se qualquer um dos argumentos da matriz fornull,, ele lança umNullPointerException e se algum dos argumentos inteiros for negativo ou fora do intervalo, ele lança umIndexOutOfBoundException.
Vamos dar uma olhada em um exemplo para copiar um array completo para outro usando a classejava.util.System:
int[] array = {23, 43, 55};
int[] copiedArray = new int[3];
System.arraycopy(array, 0, copiedArray, 0, 3);
Os argumentos que esse método leva são; uma matriz de origem, a posição inicial para copiar da matriz de origem, uma matriz de destino, a posição inicial na matriz de destino e o número de elementos a serem copiados.
Vamos dar uma olhada em outro exemplo que mostra a cópia de uma subseqüência de uma matriz de origem para um destino:
int[] array = {23, 43, 55, 12, 65, 88, 92};
int[] copiedArray = new int[3];
System.arraycopy(array, 2, copiedArray, 0, 3);
assertTrue(3 == copiedArray.length);
assertTrue(copiedArray[0] == array[2]);
assertTrue(copiedArray[1] == array[3]);
assertTrue(copiedArray[2] == array[4]);
3. A classeArrays
A classeArrays também oferece vários métodos sobrecarregados para copiar um array para outro. Internamente, ele usa a mesma abordagem fornecida pela classeSystem que vimos anteriormente. Ele fornece principalmente dois métodos,copyOf(…)ecopyRangeOf(…).
Vamos dar uma olhada emcopyOf primeiro:
int[] array = {23, 43, 55, 12};
int newLength = array.length;
int[] copiedArray = Arrays.copyOf(array, newLength);
É importante notar que a classeArrays usaMath.min(…) para selecionar o mínimo do comprimento da matriz de origem e o valor do novo parâmetro de comprimento para determinar o tamanho da matriz resultante.
Arrays.copyOfRange() usa 2 parâmetros, ‘from'e‘to', além do parâmetro de matriz de origem. A matriz resultante inclui o índice ‘from', mas o índice‘to' é excluído. Vamos ver um exemplo:
int[] array = {23, 43, 55, 12, 65, 88, 92};
int[] copiedArray = Arrays.copyOfRange(array, 1, 4);
assertTrue(3 == copiedArray.length);
assertTrue(copiedArray[0] == array[1]);
assertTrue(copiedArray[1] == array[2]);
assertTrue(copiedArray[2] == array[3]);
Ambos os métodosdo a shallow copy de objetos se aplicados em uma matriz de tipos de objetos não primitivos. Vejamos um exemplo de caso de teste:
Employee[] copiedArray = Arrays.copyOf(employees, employees.length);
employees[0].setName(employees[0].getName() + "_Changed");
assertArrayEquals(copiedArray, array);
Como o resultado é uma cópia superficial - uma alteração no nome do funcionário de um elemento da matriz original causou a alteração na matriz de cópias.
E assim - se quisermos fazer uma cópia profunda de tipos não primitivos - podemos escolher as outras opções descritas nas próximas seções.
4. Cópia de matriz comObject.clone()
Object.clone() é herdado da classeObject em uma matriz.
Vamos primeiro copiar uma matriz de tipos primitivos usando o método clone:
int[] array = {23, 43, 55, 12};
int[] copiedArray = array.clone();
E uma prova de que funciona:
assertArrayEquals(copiedArray, array);
array[0] = 9;
assertTrue(copiedArray[0] != array[0]);
O exemplo acima mostra que têm o mesmo conteúdo após a clonagem, mas contêm referências diferentes, portanto, qualquer alteração em qualquer uma delas não afetará a outra.
Por outro lado, se clonarmos uma matriz de tipos não primitivos usando o mesmo método, os resultados serão diferentes.
Ele criaa shallow copy dos elementos da matriz de tipo não primitivo, mesmo se a classe do objeto fechado implementar a interfaceCloneablee substituir o métodoclone() da classeObject.
Vamos dar uma olhada em um exemplo:
public class Address implements Cloneable {
// ...
@Override
protected Object clone() throws CloneNotSupportedException {
super.clone();
Address address = new Address();
address.setCity(this.city);
return address;
}
}
Podemos testar nossa implementação criando uma nova matriz de endereços e invocando nosso métodoclone():
Address[] addresses = createAddressArray();
Address[] copiedArray = addresses.clone();
addresses[0].setCity(addresses[0].getCity() + "_Changed");
assertArrayEquals(copiedArray, addresses);
Este exemplo mostra que qualquer alteração na matriz original ou copiada causaria a alteração na outra, mesmo quando os objetos incluídos sãoCloneable.
5. Usando a APIStream
Acontece que também podemos usar a API Stream para copiar matrizes. Vamos dar uma olhada em um exemplo:
String[] strArray = {"orange", "red", "green'"};
String[] copiedArray = Arrays.stream(strArray).toArray(String[]::new);
Para os tipos não primitivos, ele também fará uma cópia superficial dos objetos. Para aprender mais sobreJava 8 Streams, você pode iniciarhere.
6. Bibliotecas externas
Apache Commons 3 oferece uma classe de utilitário chamadaSerializationUtils que fornece um métodoclone(…). É muito útil se precisarmos fazer uma cópia profunda de uma matriz de tipos não primitivos. Ele pode ser baixado deheree sua dependência Maven é:
org.apache.commons
commons-lang3
3.5
Vamos dar uma olhada em um caso de teste:
public class Employee implements Serializable {
// fields
// standard getters and setters
}
Employee[] employees = createEmployeesArray();
Employee[] copiedArray = SerializationUtils.clone(employees);
employees[0].setName(employees[0].getName() + "_Changed");
assertFalse(
copiedArray[0].getName().equals(employees[0].getName()));
Esta classe requer que cada objeto implemente a interfaceSerializable. Em termos de desempenho, é mais lento que os métodos clone escritos manualmente para cada um dos objetos em nosso gráfico de objetos copiar.
7. Conclusão
Neste tutorial, vimos as várias opções para copiar uma matriz em Java.
O método a ser usado depende principalmente do cenário exato. Contanto que estejamos usando uma matriz de tipo primitivo, podemos usar qualquer um dos métodos oferecidos pelas classesSystemeArrays. Não deve haver nenhuma diferença no desempenho.
Para tipos não primitivos, se precisarmos fazer uma cópia profunda de um array, podemos usarSerializationUtils ou adicionar métodos clones explicitamente às nossas classes.
E como sempre, os exemplos mostrados neste artigo estão disponíveis emover on GitHub.