Prototype mode is used to create duplicate objects while maintaining performance, creating new instances by copying existing instances without knowing class information.
Unlike constructing new objects by instantiating a class, a prototype pattern generates new objects by copying an existing object.
So how do you implement the prototype pattern in java?The essence of a prototype pattern is a clone, which copies an identical object.
The implementation prototype pattern in java can be divided into two types: shallow copy and deep copy.
The shallow copy implementation prototype pattern implements a cloning interface, which is the cloning used to create the current object.Here is the code to make a shallow copy.
First, define a class that implements the clone() method within the Cloneable interface.
public class Person implements Cloneable { String name; int age; int[] a; @Override public Object clone() throws CloneNotSupportedException{ Object obj = super.clone(); return obj; } 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 int[] getA() { return a; } public void setA(int[] a) { this.a = a; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", a=" + Arrays.toString(a) + '}'; } }
public static void main(String[] args) throws CloneNotSupportedException{ Person p = new Person(); p.setAge(10); p.setName("Jack"); p.setA(new int[]{1}); System.out.println("Precloning p Value of:"+p); Person p2 = (Person)p.clone(); System.out.println("Unmodified before cloning p2 Value of:"+p2); p2.setAge(11); p2.setName("Tom"); int[] a = p2.getA(); a[0] = 2; p2.setA(a); System.out.println("Modify after cloning p2 Value of, p2 The value of:"+p2); System.out.println("Modify after cloning p2 Value of, p The value of:"+p); }
Value of pre-clone p: Person{name='Jack', age=10, a=[1]} The value of p2 was not modified before cloning: Person{name='Jack', age=10, a=[1]} Modify p 2 values after cloning: Person{name='Tom', age=11, a=[2]} Modify the value of p 2 after cloning, the value of p is Person{name='Jack', age=10, a=[2]}
From the above code, we find that modifying the values of String and int types of p2 cloned from P does not change the values of the corresponding types of p, but when modifying the values of reference type int[], the corresponding types of P also change, which means that for basic types, a shallow copy copies the values of member variables of value type, and for quotationCopy references with variables of type, not with referenced objects.String is a special type whose data is placed in a constant pool. The modification to p2 is to point the reference to its String type from "Jack" to "Tom", while the String type of P still points to "Jack" and has not changed.
So, there are many times when I don't want changes to the copied object to affect the original object, and then we need to make a deep copy.
Deep copy: Make a value copy of a member variable of a value type, copy a reference to a variable of a reference type, and copy the referenced object.Simply put, deep copies are individual copies of attributes that simply copy references without copying objects.
First method: Copy the object of the reference type again individually
public class Person implements Cloneable { String name; int age; int[] a; @Override public Person clone() throws CloneNotSupportedException{ Person person = (Person)super.clone(); person.a = this.a.clone(); return person; } 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 int[] getA() { return a; } public void setA(int[] a) { this.a = a; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", a=" + Arrays.toString(a) + '}'; } }
A deep copy can be made by directly copying a reference to the int[] array type in the clone() method in a separate copy.
The second method is to serialize an object into a byte sequence using a javaIO stream. By default, the entire object graph of the object is serialized, and then the deep copy is perfectly achieved by deserializing.
public static void main(String[] args) throws Exception{ Person person = new Person(); person.setAge(10); person.setName("Jack"); person.setA(new int[]{1}); ByteArrayOutputStream bos = new ByteArrayOutputStream(); //ObjectOutputStream Object Output Stream ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(person); oos.flush(); //ObjectOutputStream Object Input Stream ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); Person person2 = (Person)ois.readObject(); System.out.println("Modify after deep copy person2 Value of:"+person2); person2.setName("Tom"); person2.setAge(12); int[] a = person2.getA(); a[0] = 3; person2.setA(a); System.out.println("Modify after deep copy person2 Value of:"+person2); System.out.println("Modify after deep copy person2 Value of, person The value is:"+person); }
Modify person2 values after deep copy: Person{name='Jack', age=10, a=[1]} Modify person2 values after deep copy: Person{name='Tom', age=12, a=[3]} Modify person 2 values after deep copy, person values are Person{name='Jack', age=10, a=[1]}
We see that modifying person2 values does not affect person values after deep copy.It is important to note that if an attribute is modified with a transient keyword, it will not be serialized.