Antes de entrar oficialmente no tópico, vamos primeiro entender os conceitos de cópia profunda e pré-cópia:
Cópia leve:
Um novo objeto será criado, que possui uma cópia exata do valor da propriedade do objeto original. Se o atributo for um tipo básico, o valor do tipo básico será copiado; Se o atributo for um endereço de memória, o endereço da memória será copiado; portanto, se um objeto alterar esse endereço, ele afetará outro objeto;
Cópia profunda:
Você não apenas deseja copiar todos os valores variáveis de membro não referenciado do objeto, mas também precisa criar uma nova instância para variáveis de membro do tipo de referência e inicializá-lo com o valor formal da instância do parâmetro;
Depois de entender o conceito, vamos testar se as operações de atribuição de objetos comuns são cópias profundas ou cópia rasa:
Código de teste:
classe pública de profundidade {public static void main (string [] args) {cópia primeiro = new cópia ("hzw", 24); Copiar segundo = primeiro; Second.Name = "Shanxi"; System.out.println (primeiro.name); // saída shanxi}} classe cópia {public string name; INT AGRIBUIL PÚBLICA; cópia pública (nome da string, int age) {this.name = name; this.age = idade; }} Pode -se descobrir que, após a segunda modificação do valor do atributo de nome para Shanxi, o valor do primeiro nome do atributo também se torna Shanxi. Isso mostra que as atribuições de objetos comuns pertencem a cópias superficiais;
Depois de entender se a atribuição entre objetos é uma cópia rasa, vamos ver se a clonagem é uma cópia profunda ou uma cópia rasa. O código de teste é ativar o objeto de cópia acima para implementar o método clone na interface clonável:
classe pública de profundidade {public static void main (string [] args) {cópia primeiro = new cópia ("hzw", 24); Copiar segundo = nulo; tente {segundo = (cópia) primeiro.clone (); } catch (clonenotsupportEdException e) {e.printStackTrace (); } Second.Name = "Shanxi"; System.out.println(first.name);//Output: hzw System.out.println(first);//Output: com.hzw.day33.Copy@7f39ebdb System.out.println(second);//Output: com.hzw.day33.Copy@33abb81e } } class Copy implements Cloneable { public String name; INT AGRIBUIL PÚBLICA; cópia pública (nome da string, int age) {this.name = name; this.age = idade; } @Override Protected Object clone () lança CLONENOTSupportEdException {return super.clone (); }}Pode -se observar que o objeto criado originalmente primeiro e o objeto clonado em segundo lugar são duas instâncias; portanto, a modificação do atributo de nome em segundo não afetará o atributo de nome no primeiro; No entanto, não podemos simplesmente pensar que a clonagem é uma cópia profunda, como o exemplo a seguir:
classe pública DepthCopy {public static void main (string [] args) {aluno estudante = novo aluno (95); Cópia primeiro = nova cópia ("hzw", 24, aluno); Copiar segundo = nulo; tente {segundo = (cópia) primeiro.clone (); } catch (clonenotsupportEdException e) {e.printStackTrace (); } Second.Name = "Shanxi"; segundo.student.score = 60; System.out.println (primeiro == Second); // false System.out.println (primeiro.student == Second.student); // true system.out.println (primeiro.student.score); // 60}} classe Copy implementa cloneable {public string name; INT AGRIBUIL PÚBLICA; estudante público; cópia pública (nome da string, idade int, estudante) {this.name = name; this.age = idade; this.student = aluno; } @Override Protected Object clone () lança CLONENOTSupportEdException {return super.clone (); }} classe Student {public int Score; public Student (Int Score) {this.score = Score; }}Você viu isso? Criamos em segundo lugar através da clonagem, e é óbvio que o primeiro e o segundo são duas instâncias, porque a saída do primeiro == segundo é falsa, mas o aluno objetos no primeiro e segundo é o mesmo. Depois de modificar o valor da pontuação do aluno até o segundo, a pontuação do aluno também mudou. Isso significa que o aluno em primeiro e segundo é o mesmo. Isso significa que a clonagem é uma cópia rasa. Se quisermos implementar uma cópia profunda da clonagem, devemos permitir que o objeto do aluno no objeto Copy também implemente o método clone na interface clonável, e o método clone em cópia retorna um clone de aluno, para que o aluno possa ser único. O código modificado é o seguinte:
classe pública DepthCopy {public static void main (string [] args) {aluno estudante = novo aluno (95); Cópia primeiro = nova cópia ("hzw", 24, aluno); Copiar segundo = nulo; tente {segundo = (cópia) primeiro.clone (); } catch (clonenotsupportEdException e) {e.printStackTrace (); } Second.Name = "Shanxi"; segundo.student.score = 60; System.out.println (primeiro == Second); // false System.out.println (primeiro.student == Second.student); // false System.out.println (primeiro.student.score); // 95 System.out.println (Second.student.Score); // 60}} cópia da classe cópia INT AGRIBUIL PÚBLICA; estudante público; cópia pública (nome da string, idade int, estudante) {this.name = name; this.age = idade; this.student = aluno; } @Override Protected Object clone () lança CLONENOTSupportEdException {copy cópia = (copy) super.clone (); cópia.student = (aluno) student.clone (); cópia de retorno; }} classe Student implementa clonável {public int escore; public Student (Int Score) {this.score = Score; } @Override Protected Object clone () lança CLONENOTSupportEdException {return super.clone (); }} Você pode ver que o primeiro e o segundo, primeiro. Portanto, depois de modificarmos a pontuação do segundo aluno, isso não afeta o valor da pontuação do aluno no primeiro, alcançando o objetivo de cópia profunda;
No entanto, se você pensar com cuidado, o problema surgirá. Se também houver atributos dos tipos de referência na aula de estudantes em nosso exemplo acima, como a aula da faculdade, devemos deixar a aula da faculdade implementar a interface clonável e depois chamar o método do clone da classe College na clone do método da aula de estudante e chamar o método de clone da classe estudantil no método clone da aula de cópia. Eu descobri que se foi. Esse processo é tão complicado. Todos os tipos de referência relevantes na classe devem implementar a interface clonável. Eu sinto que é tão problemático, ok, a próxima coisa é ser incrível.
A melhor maneira de resolver o problema de cópia profundo é usar a serialização, para que todas as classes não precisem implementar a interface clonável, apenas serialize e desserialize diretamente. Vamos dar uma olhada.
importar java.io.file; importar java.io.fileInputStream; importar java.io.fileOutputStream; importar java.io.ObjectInputStream; importar java.io.ObjectOutputStream; importar java.io.serializable; classe pública DepthCopy {public static void main (string [] args) {College School = New College ("Nongda"); Estudante estudante = novo aluno (95, escola); Cópia de cópia = nova cópia ("hzw", 23, aluno); Copie outro = null; // indica a instância da classe desapealizada // serialize a operação de serialização, tente {FileOutputStream fos = new FileOutputStream (new File ("d: /copy.txt")); ObjectOutputStream ooS = new ObjectOutputStream (Fos); oos.WriteObject (cópia); } catch (Exceção e) {e.printStackTrace (); } // serialize a operação de deserivalização FILEInputStream fis; tente {fis = new FileInputStream (novo arquivo ("d: /copy.txt")); ObjectInputStream ois = new ObjectInputStream (fis); outro = (cópia) ois.readObject (); } catch (Exceção e) {e.printStackTrace (); } System.out.println (copy == outro); // false System.out.println (copy.student == outro.student); // false System.out.println (copy.student.school == outro.student.school); // false.student.scool.schoolname = " System.out.println (copy.student.school.schoolname); // nongda}} classe cópia implementa serializável {name public string; INT AGRIBUIL PÚBLICA; estudante público; cópia pública (nome da string, idade int, estudante) {this.name = name; this.age = idade; this.student = aluno; }} classe Student implementa serializável {public int escore; Escola Public College; Public Student (Int Score, College School) {this.score = Score; this.school = escola; }} classe College implementa serializável {public String SchoolName; Public College (String SchoolName) {this.schoolname = SchoolName; }} A partir da saída, podemos ver que o objeto gerado após a desserialização é uma cópia do objeto original e não possui nenhum relacionamento com o objeto original, exceto o mesmo valor de atributo. Portanto, quando modificamos o nome da escola do objeto gerado pela deseralização para "Wuda", não modificamos o nome da escola da instância original e ainda produzimos "Nongda", por isso alcançamos o verdadeiro efeito de cópia profunda. No entanto, para alcançar a serialização, todas as classes relevantes devem implementar a interface serializável, que é sempre mais conveniente do que implementar a interface clonável e o método clone.
O exposto acima é uma explicação detalhada de cópias profundas e superficiais de Java. Se você precisar, consulte -o.