java.lang.Cloneable
Ele também java.io.Serializable
pertence à interface marcada e não define nenhum método e atributo.
Uma classe deseja usar o método clone
重写clone()方法
, Porque o modificador de clone () de Object está protegido;
@HotSpotIntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;
实现Cloneable接口
Caso contrário, CloneNotSupportedException será lançado.
Tipo de clone
浅拷贝
, Ao copiar um objeto, apenas o próprio objeto e as variáveis básicas no objeto são copiados, e o objeto apontado pela referência contida no objeto não é copiado深拷贝
, Não apenas copia o próprio objeto, mas também todos os objetos apontados pelas referências contidas no objeto de cópia
Dar uma castanha
Aqui, Usuário e Telefone são usados como exemplos.
O método principal usado para testar a cópia superficial e a cópia profunda é o seguinte:
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
// 预置数据
Phone phone1 = new Phone();
String number = "11111111111";
phone1.setPhoneNum(number);
String name = new String("dkangel");
int age = 24;
User user1 = new User(name, age, phone1);
User user2 = (User) user1.clone();
System.out.println("对象是否相等:" + (user1 == user2));
System.out.println("类的类型是否相等:" + (user1.getClass() == user2.getClass()));
System.out.println("age属性是否相等:" + (user1.getAge() == user2.getAge()));
System.out.println("name属性是否相等:" + (user1.getName() == user2.getName()));
System.out.println("对象的对象属性Phone是否相等:" + (user1.getPhone() == user2.getPhone()));
}
}
Cópia superficial
Copie apenas o próprio objeto, Phone não precisa implementar a interface Cloneable e substituir o método clone ().
public class Phone {
private String phoneNum;
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
}
public class User implements Cloneable {
private String name;
private int age;
private Phone phone;
public User(String name, int age, Phone phone) {
this.name = name;
this.age = age;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
user2是user1的浅拷贝,只拷贝user1对象本身,未拷贝成员变量phone,所以两者phone对象相等
Cópia profunda
Não apenas copie o próprio objeto, mas também copie todos os objetos apontados pelo objeto, portanto, a classe Phone também suporta clone.
public class Phone implements Cloneable{
private String phoneNum;
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
User.java apenas cole o método clone () aqui, os outros são consistentes com o clone raso
public class User implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
User user = (User) super.clone();
user.phone = (Phone) user.getPhone().clone();
return user;
}
}
user2是user1的深拷贝,拷贝user1本身的同时也拷贝一份phone1对象,两者phone对象不再相等
Compreenda a cópia superficial e a cópia profunda em combinação com a partição de memória JVM
Como você pode ver na figura acima, a memória JVM é dividida em cinco partes: heap, área de método, contador de programa, pilha de máquina virtual e pilha de método local. Aqui, nos concentramos apenas em
- Objeto de armazenamento
堆
- Armazene tipos de dados básicos e referências de objetos
虚拟机栈
- Armazenar informações básicas
方法区
浅拷贝解读
Interprete o método principal de CloneTest de cima para baixo no modo e obtenha o diagrama de distribuição dos seguintes objetos na JVM.
Aqui usamos o 句柄模式
objeto de acesso (e o modo de endereço direto), uma interpretação simples
O novo objeto phone1 é armazenado no pool de instâncias do heap; o número da string é criado entre aspas, portanto, é armazenado no pool de constantes da string no heap; o nome da string é criado com new, por isso é armazenado no Pool de instâncias de string; idade pertence aos dados básicos. O tipo é, portanto, armazenado na pilha de máquina virtual; o usuário1 aloca memória no heap e cria o objeto usuário2 por meio dos dados do próprio objeto clone usuário1 e os atributos nome / idade / o telefone do usuário2 são compartilhados com o usuário1.
深拷贝解读
O user2 criado pela cópia profunda não compartilha mais o atributo phone com o objeto user1. A cópia profunda não apenas copia o próprio user1, mas também copia o objeto phone1 do usuário1.
Apenas as diferenças da cópia superficial são coladas aqui,user2的phone属性由指向phone1改为指向phone2
Se houver algum erro, sinta-se à vontade para apontá-lo, paz