Cet article vous apporte une analyse détaillée du clonage superficiel et du clonage profond dans les objets Java (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Dans la classe de base Object, il existe une méthode appelée clone, qui génère un clone de l'objet précédent. L'objet cloné est une copie de l'objet original. En présence de types référence, il existe un clonage profond. La différence entre le clonage superficiel et le clonage superficiel est que s'il existe un attribut de type référence dans l'objet cloné, le clonage profond fera une copie complète de l'attribut, tandis que le clonage superficiel ne copie qu'une référence. à l'attribut. Tout d'abord, jetons un coup d'œil à quelques problèmes mineurs faciles à résoudre
La méthode clone appartient à la classe Object, et non à l'interface Cloneable. C'est juste une interface de marqueurs. implémente l'interface.La classe a une sorte deLa fonction de marquage d'interface.Il existe trois interfaces de marquage courantes : Sérialisable, Cloneable et RandomAccess.Si l'interface Cloneable n'est pas implémentée, l'appel de la méthode clone provoquera une exception CloneNotSupportedException.
La méthode clone dans la classe Object est modifiée avec protected, ce qui signifie que si nous ne remplaçons pas cette méthode dans la sous-classe, elle ne sera pas accessible en dehors de la sous-classe, car cette autorisation protégée n'est accessible que par l'objet. Les packages et les sous-classes peuvent y accéder, ce qui vérifie également la déclaration selon laquelle les sous-classes peuvent agrandir le modificateur d'autorisation lors du remplacement des méthodes de la classe parent, mais pas le réduire.
protected native Object clone() throws CloneNotSupportedException;
Remplacer la méthode clone en interne n'appelle que la méthode clone de la classe parent. En fait, il s'agit d'étendre les droits d'accès. Bien sûr, vous pouvez changer protected en public, et vous n'en avez pas besoin. de le réécrire si vous héritez dans le futur. Bien sûr, il ne s'agit que de la fonction de clonage pour le clonage superficiel, et le clonage profond doit être modifié.
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
Si l'attribut est String et que String est également une classe, String est-il un type référence ? String se comporte comme un type de base. L'essentiel est que String ne peut pas être modifié, les deux références pointent vers la même String. Cependant, lorsque l'une d'elles est modifiée, la valeur de String n'est pas modifiée, mais une nouvelle. La chaîne est générée. La référence modifiée pointe vers la nouvelle chaîne. L'apparence ressemble au type de base.
Le clonage superficiel signifie que les attributs de type référence ne peuvent pas être complètement copiés. La classe Utilisateur contient l'attribut de note Mark est composé de chinois, de mathématiques, etc. Exemples de clonage superficiel. échec
class Mark{ private int chinese; private int math; public Mark(int chinese, int math) { this.chinese = chinese; this.math = math; } public void setChinese(int chinese) { this.chinese = chinese; } public void setMath(int math) { this.math = math; } @Override public String toString() { return "Mark{" + "chinese=" + chinese + ", math=" + math + '}'; } } public class User implements Cloneable{ private String name; private int age; private Mark mark; public User(String name, int age,Mark mark) { this.name = name; this.age = age; this.mark = mark; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", mark=" + mark + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Mark mark = new Mark(100,99); User user = new User("user",22,mark); User userClone = (User) user.clone(); System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); //修改引用类型的mark属性 user.mark.setMath(60); System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
Le résultat de sortie est :
Utilisateur d'origine : Utilisateur{name='user', age=22, mark=Mark{chinese=100, math=99}}
Utilisateur clone : Utilisateur{name='user', age=22, mark=Mark{chinese=100, math=99}>
Utilisateur d'origine modifié : Utilisateur{name='user', age=22, mark =Mark{chinese=100, math=60}>
Utilisateur clone modifié : Utilisateur{name='user', age=22, mark=Mark{chinese=100, math=60}}
Il est clair qu'une fois la marque de l'utilisateur modifiée, l'utilisateur cloné est également modifié. Et si vous ne voulez pas être affecté, vous avez besoin d’un clonage profond.
Étant donné que le type référence ne peut pas être complètement cloné, le type référence implémente également l'interface Cloneable et réécrit le clone méthode , la méthode clone de la classe User appelle la méthode clone de l'attribut, c'est-à-dire l'appel imbriqué de la méthode
class Mark implements Cloneable{ private int chinese; private int math; public Mark(int chinese, int math) { this.chinese = chinese; this.math = math; } public void setChinese(int chinese) { this.chinese = chinese; } public void setMath(int math) { this.math = math; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Mark{" + "chinese=" + chinese + ", math=" + math + '}'; } } public class User implements Cloneable{ private String name; private int age; private Mark mark; public User(String name, int age,Mark mark) { this.name = name; this.age = age; this.mark = mark; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", mark=" + mark + '}'; } @Override protected Object clone() throws CloneNotSupportedException { User user = (User) super.clone(); user.mark = (Mark) this.mark.clone(); return user; } public static void main(String[] args) throws CloneNotSupportedException { Mark mark = new Mark(100,99); User user = new User("user",22,mark); User userClone = (User) user.clone(); System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); //修改引用类型的mark属性 user.mark.setMath(60); System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
Le résultat de sortie est :
Utilisateur d'origine : Utilisateur {name='user' , age=22, mark=Mark{chinese=100, math=99}}
Cloner l'utilisateur : Utilisateur{name='user', age=22, mark=Mark{chinese=100, math=99}}
L'utilisateur d'origine modifié : User{name='user', age=22, mark=Mark{chinese=100, math=60}}
L'utilisateur clone modifié : User{name= 'user' , age=22, mark=Mark{chinese=100, math=99}}
La méthode précédente suffit à répondre à nos besoins, mais si le classe Il existe de nombreuses relations entre eux, ou certains attributs sont des tableaux. Les tableaux ne peuvent pas implémenter l'interface Cloneable (nous pouvons copier manuellement le tableau dans la méthode clone), mais nous devons écrire la méthode clone à la main à chaque fois, ce qui est très gênant. , et la méthode de sérialisation nécessite uniquement d'implémenter une interface sérialisable pour chaque classe, qui est également une interface de marque. Enfin, les opérations de sérialisation et de désérialisation sont utilisées pour atteindre l'objectif de clonage (y compris la copie de tableaux). Pour en savoir plus sur la sérialisation et la désérialisation, veuillez vous référer à l'article suivant
import java.io.*; class Mark implements Serializable { private int chinese; private int math; public Mark(int chinese, int math) { this.chinese = chinese; this.math = math; } public void setChinese(int chinese) { this.chinese = chinese; } public void setMath(int math) { this.math = math; } @Override public String toString() { return "Mark{" + "chinese=" + chinese + ", math=" + math + '}'; } } public class User implements Serializable{ private String name; private int age; private Mark mark; public User(String name, int age,Mark mark) { this.name = name; this.age = age; this.mark = mark; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", mark=" + mark + '}'; } public static void main(String[] args) throws IOException, ClassNotFoundException { Mark mark = new Mark(100,99); User user = new User("user",22,mark); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(user);//序列化 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); User userClone = (User) oi.readObject();//反序列化 System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); user.mark.setMath(59); System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
Résultat de sortie :
Utilisateur d'origine : Utilisateur{name='user', age=22, mark=Mark{ Chinese=100, math=99}}
Utilisateur clone : Utilisateur{name='user', age=22, mark=Mark{chinese=100, math=99}>
Utilisateur d'origine modifié : Utilisateur{name ='user', age=22, mark=Mark{chinese=100, math=60}}
Utilisateur clone modifié : Utilisateur{name='user', age=22, mark=Mark{chinois=100, math =99}}
Cloner avec les attributs du tableau
import java.io.*; import java.util.Arrays; public class User implements Serializable{ private String name; private int age; private int[] arr; public User(String name, int age, int[] arr) { this.name = name; this.age = age; this.arr = arr; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", arr=" + Arrays.toString(arr) + '}'; } public static void main(String[] args) throws IOException, ClassNotFoundException { int[] arr = {1,2,3,4,5,6}; User user = new User("user",22,arr); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(user);//序列化 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); User userClone = (User) oi.readObject();//反序列化 System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); user.arr[1] = 9; System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!