文章目錄
1、爲什麼要clone
當一個對象需要被多人操作,但是又不相互影響,需要保持原對象的狀態,這時就會克隆出許多不同的對象。
2、new 對象和 clone 對象的區別
new 操作 本質是操作內存。程序在執行new操作的時候,首先看到的是new
操作符後面的類型,因爲知道了類型,才能知道要分配多大的內存空間。分配完內存後,在調用構造函數,填充對象的各個域,這一步叫做對象的初始化。構造方法創建完成之後,可以吧他的引用(地址)發佈到外部,就可以在外部引用操縱這個對象。
clone 在第一步 和new 相似,都是分配內存,調用clone 方法時,分配的內存和原對象(調用clone方法的原對象),然後再使用對象中對應的各個域,填充新的對象的域,填充完成後,clone 方法返回,一個新的相同的對象被創建,同樣可以把新的對象那個的引用發佈到外部。
3、clone 對象的使用
1) 我們 先看 一下 賦值引用;
package com.example.lum.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Person testObjectOne;
Person testObjectTwo;
testObjectOne = new Person(28,"lu"); //新建 一個對象 one
testObjectTwo = testObjectOne; //將 one 賦值給 Twos
System.out.println("``````````````");
System.out.println(testObjectOne);
System.out.println(testObjectTwo);
System.out.println("``````````````");
}
class Person {
private int age;
private String name ;
public Person(int age,String name){
this.age = age;
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
}
}
log 顯示:
我們可以看到打印的地址值是相同的,那肯定是一個對象。
testObjectOne,testObjectTwo 只是引用而已,都指向一個相同的對象 Person。
可以把這種現象叫做引用的複製:
2)下面我們看一下克隆一個對象:
這個時候 Person 類需要繼承 Cloneable 實現 clone 接口
package com.example.lum.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Person testObjectOne;
Person testObjectTwo;
testObjectOne = new Person(28,"lu"); //新建 一個對象 one
testObjectTwo = (Person) testObjectOne.clone(); //將 one 克隆Two
System.out.println("``````````````");
System.out.println(testObjectOne);
System.out.println(testObjectTwo);
System.out.println("``````````````");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
class Person implements Cloneable {
private int age;
private String name ;
public Person(int age,String name){
this.age = age;
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
}
}
log顯示:
我們可以看到
4、clone 分爲 淺拷貝 和 深拷貝
就像我們的類一樣,裏面有 變量,age ,name 。
age 是基礎數據類型,在clone 時直接 將一個4字節數值拷貝過來,
name 是String 類型,它是一個引用,指向String 對象。那麼對它的clone有兩種,一種是將引用拷給新的對象,一種是將最它指向的字符串對象clone出來,賦值給新的對象。
這兩種方式 一個是淺拷貝,一個是深拷貝
1) 淺拷貝
2)、深拷貝
3)、淺拷貝示例
我們上面代碼就是淺拷貝示例,我們比較下拷貝對象裏的 name 地址 和 原對象地址是否一樣
package com.example.lum.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Person testObjectOne;
Person testObjectTwo;
testObjectOne = new Person(28,"lu"); //新建 一個對象 one
testObjectTwo = (Person) testObjectOne.clone(); //將 one 賦值給 Twos
System.out.println("``````````````");
System.out.println(testObjectOne.getName());
System.out.println(testObjectTwo.getName());
System.out.println((testObjectOne.getName() == testObjectTwo.getName()));
System.out.println("``````````````");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
class Person implements Cloneable {
private int age;
private String name ;
public Person(int age,String name){
this.age = age;
this.name = name;
}
public int getAge(){
return this.age;
}
public String getName (){
return this.name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
}
}
打印的 log:
4)、深拷貝的例子
我們在年齡,姓名,之上添加一個靈魂
package com.example.lum.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Person testObjectOne;
Person testObjectTwo;
testObjectOne = new Person(28,"lu",new Soul()); //新建 一個對象 one
testObjectTwo = (Person) testObjectOne.clone(); //將 one 賦值給 Twos
System.out.println("``````````````");
System.out.println(testObjectOne.getName());
System.out.println(testObjectTwo.getName());
System.out.println((testObjectOne.getName() == testObjectTwo.getName()));
System.out.println(testObjectOne.getSoul());
System.out.println(testObjectTwo.getSoul());
System.out.println((testObjectOne.getSoul() == testObjectTwo.getSoul()));
System.out.println("``````````````");
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
class Person implements Cloneable {
private int age;
private String name ;
private Soul soul;
public Person(int age,String name, Soul soul){
this.age = age;
this.name = name;
this.soul = soul;
}
public int getAge(){
return this.age;
}
public String getName (){
return this.name;
}
public Soul getSoul (){
return this.soul;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone(); // 回調 clone 方法 新建Person 對象
person.soul = (Soul) soul.clone(); //同時 對象 裏的 靈魂對象 clone 自身父類
return person;
}
}
//新建靈魂對象 同時 也 添加 Cloneable 接口
class Soul implements Cloneable{
public Soul(){}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Soul)super.clone();
}
}
}
log :
我們可以看到 靈魂的對象他們clone 前後的地址是不一樣的。
就是深克隆 ,克隆的對象裏的對象也要克隆。