java之clone方法的使用
首先看一下jdk中對clone方法的解釋:
大概意思是說:返回一個要克隆物件的副本,克隆的型別依賴被克隆物件,換句話說:克隆後的物件型別與被克隆物件的型別相同。
一、簡單用法
只需要在需要clone的物件上實現(implements)Cloneable介面,然後再在類中加上clone方法,在方法中只需要呼叫super.clone(),根據自己的需要實現即可。
public class Student implements Cloneable { private String name; private int age; 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; } @Override protected Student clone() throws CloneNotSupportedException { return (Student)super.clone(); } public static void main(String[] args) { Student stu = new Student(); stu.setAge(1); stu.setName("aa"); System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName()); try { Student sC = stu.clone(); System.out.println(sC + " sC.age: " + sC.getAge() + " sC.name: " + sC.getName()); sC.setAge(12); sC.setName("bb"); System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName()); System.out.println(sC + " sC.age: " + sC.getAge() + " sC.name: " + sC.getName()); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
輸出結果:
[email protected] age: 1 name: aa
[email protected] sC.age: 1 sC.name: aa
[email protected] age: 1 name: aa
[email protected] sC.age: 12 sC.name: bb
分析結果:1、根據輸出結果中前邊的類名,可以得出被克隆物件的與原來的物件是同一種類型。2、根據記憶體地址(hashcode)知道,被克隆物件的與原來的物件是存在於記憶體中的不同的兩個物件。所以後邊有一個賦值,對原來物件沒有任何影響。
二、“影子”克隆與深度克隆
首先看一個例子:
輸出結果:class Bag{//學生的書包 private int width; private String logo; public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public String getLogo() { return logo; } public void setLogo(String logo) { this.logo = logo; } } public class Student2 implements Cloneable { private String name; private int age; private Bag bag; public Bag getBag() { return bag; } public void setBag(Bag bag) { this.bag = bag; } 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; } @Override protected Student2 clone() throws CloneNotSupportedException { return (Student2)super.clone(); } public static void main(String[] args) { Student2 stu = new Student2(); stu.setAge(1); stu.setName("aa"); Bag b = new Bag(); b.setWidth(10); b.setLogo("Nike"); stu.setBag(b); printStudent(stu); try { Student2 sC = stu.clone(); printStudent(sC); sC.setAge(12); sC.setName("bb"); sC.getBag().setWidth(100);//改變書包的屬性 sC.getBag().setLogo("JNike"); printStudent(stu); printStudent(sC); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 輸出 * @param stu */ private static void printStudent(Student2 stu) { System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName() + " bag: " + stu.getBag() + "(" + stu.getBag().getLogo() + " width: " + stu.getBag().getWidth() + ")"); } }
[email protected] age: 1 name: aa bag: [email protected](Nike width: 10)
[email protected] age: 1 name: aa bag: [email protected](Nike width: 10)
[email protected] age: 1 name: aa bag: [email protected](JNike width: 100)
[email protected] age: 12 name: bb bag: [email protected](JNike width: 100)
分析:發現是不是跟預期的不太一樣,通過第二個同學改變書包,但是第一個同學的書包也被改變了。並且通過記憶體地址可知,他們是同一物件(書包)。原因:呼叫Object類中clone()方法產生的效果是:先在記憶體中開闢一塊和原始物件一樣的空間,然後原樣拷貝原始物件中的內 容。對基本資料型別,這樣的操作是沒有問題的,但對非基本型別變數,我們知道它們儲存的僅僅是物件的引用,這也導致clone後的非基本型別變數和原始對 象中相應的變數指向的是同一個物件。 這就是所謂的“影子”克隆。
解決方案:深度克隆,既是對裡邊的引用也要克隆。以下是實現:
class Bag implements Cloneable{//學生的書包
private int width;//寬
private String logo;//品牌
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
@Override
protected Bag clone() throws CloneNotSupportedException {
return (Bag)super.clone();
}
}
public class Student3 implements Cloneable {
private String name;
private int age;
private Bag bag;
public Bag getBag() {
return bag;
}
public void setBag(Bag bag) {
this.bag = bag;
}
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;
}
@Override
protected Student3 clone() throws CloneNotSupportedException {
Student3 stu = (Student3)super.clone();
stu.bag = bag.clone();
return stu;
}
public static void main(String[] args) {
Student3 stu = new Student3();
stu.setAge(1);
stu.setName("aa");
Bag b = new Bag();
b.setWidth(10);
b.setLogo("Nike");
stu.setBag(b);
printStudent(stu);
try {
Student3 sC = stu.clone();
printStudent(sC);
sC.setAge(12);
sC.setName("bb");
sC.getBag().setWidth(100);//改變書包的屬性
sC.getBag().setLogo("JNike");
printStudent(stu);
printStudent(sC);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 輸出
* @param stu
*/
private static void printStudent(Student3 stu) {
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName() +
" bag: " + stu.getBag() + "(" + stu.getBag().getLogo() + " width: " +
stu.getBag().getWidth() + ")");
}
}
輸出:
[email protected] age: 1 name: aa bag: [email protected](Nike width: 10)
[email protected] age: 1 name: aa bag: [email protected](Nike width: 10)
[email protected] age: 1 name: aa bag: [email protected](Nike width: 10)
[email protected] age: 12 name: bb bag: [email protected](JNike width: 100)
與我們期望的相同了。
三、是不是萬事大吉了?
注意:要知道不是所有的類都能實現深度clone的。例如,StringBuffer,看一下 JDK API中關於StringBuffer的說明,StringBuffer沒有過載clone()方法,更為嚴重的是StringBuffer還是一個 final類,這也是說我們也不能用繼承的辦法間接實現StringBuffer的clone。如果一個類中包含有StringBuffer型別物件或和 StringBuffer相似類的物件,我們有兩種選擇:要麼只能實現影子clone,要麼自己重新生成物件: new StringBuffer(oldValue.toString()); 進行賦值。
你是不是想問上邊例子中的String呢,難道實現了clone?(查詢String.java原始碼,發現並沒有)通過以下的例子為你解答疑惑:
class StrCloneDemo implements Cloneable {
public String str;
public StringBuffer strBuff;
public Object clone() throws CloneNotSupportedException {
return (StrCloneDemo) super.clone();
}
}
public class StrCloneDemoTest {
public static void main(String[] a) {
StrCloneDemo scd1 = new StrCloneDemo();
scd1.str = new String("abcdefghijk");
scd1.strBuff = new StringBuffer("rstuvwxyz");
System.out.println("before clone,scd1.str = " + scd1.str);
System.out.println("before clone,scd1.strBuff = " + scd1.strBuff);
StrCloneDemo scd2 = null;
try {
scd2 = (StrCloneDemo) scd1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
scd2.str = scd2.str.substring(0, 3);
scd2.strBuff = scd2.strBuff.append("RSTUVWXYZ");
System.out.println("******************************************");
System.out.println("after clone,scd1.str = " + scd1.str);
System.out.println("after clone,scd1.strBuff = " + scd1.strBuff);
System.out.println("******************************************");
System.out.println("after clone,scd2.str = " + scd2.str);
System.out.println("after clone,scd2.strBuff = " + scd2.strBuff);
}
}
輸出:
before clone,scd1.str = abcdefghijk
before clone,scd1.strBuff = rstuvwxyz
******************************************
after clone,scd1.str = abcdefghijk
after clone,scd1.strBuff = rstuvwxyzRSTUVWXYZ
******************************************
after clone,scd2.str = abc
after clone,scd2.strBuff = rstuvwxyzRSTUVWXYZ
分析:String型別的變數好象已經實現了深度clone,因為對scd2.str的改動並沒有影響到scd1.str!實質上,在clone的時候scd1.str與scd2.str仍然是引用,而且都指向了同一個 String物件。但在執行c2.str = c2.str.substring(0,5)的時候,生成了一個新的String型別,然後又賦回給scd2.str。這是因為String被 Sun公司的工程師寫成了一個不可更改的類(immutable
class),在所有String類中的函式都不能更改自身的值。類似的,String類中的其它方法也是如此,都是生成一個新的物件返回。當然StringBuffer還是原來的物件。
相關推薦
java之clone方法的使用
首先看一下jdk中對clone方法的解釋: 大概意思是說:返回一個要克隆物件的副本,克隆的型別依賴被克隆物件,換句話說:克隆後的物件型別與被克隆物件的型別相同。 一、簡單用法 只需要在需要clone的物件上實現(implements)Cloneable介面,然後再在類中加
Java Object物件之clone方法
原文:http://blog.csdn.net/bigconvience/article/details/25025561 克隆的目的:快速建立一個已有物件的副本。 克隆的步驟: 建立一個物件將原有物件的資料匯入到新建立的資料中 1. Object的clone()原始
【JAVA之反射方法的應用】
JAVA之反射的應用 import java.util.HashMap; import java.util.Map; public class Child extends Parent { public int add(int a,int b){ return a+b; }
Java中clone()方法的使用
Java程式設計思想 物件克隆是指建立已有物件的一個拷貝,如果想要修改一個物件,但同時不想改變呼叫者的物件,那麼克隆會是很好的解決方式。 在Java中,實現物件的克隆只需要覆蓋Object提供的clone()方法,並將方法訪問級別改為public,同時要注意物件所屬類必須實
Java之靜態方法中的內部類
靜態方法中不能直接建立內部類,為什麼呢?在外部呼叫靜態方法時,可以使用"類名.方法名"的方式,也可以使用"物件名.方法名"的方式。而例項方法只有後面這種方式。也就是說,呼叫靜態方法可以無需建立物件。 靜態方法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變數和靜態方法
Java中Clone方法
一. Clone的原理: 將現有的物件克隆一份,包括給現有物件屬性所賦的值,形成一個新的物件,相當於在記憶體中將現有物件拷貝一份,並重新分配記憶體空間,拷貝後的物件和現有的物件相當於物理隔離了,操作克隆物件不會影響原來物件。 二. Clone
java中clone方法的理解(深拷貝、淺拷貝)
前言: java中的clone一直是一個老生常談的問題,另外關於克隆網上也有很多的寫過這方面的問題。 我在這裡記錄一下我遇到的問題和使用clone的方法。 知識點一:什麼是淺拷貝? 我們這裡說的淺拷貝是指我們拷貝出來的物件內部的引用型別
Java中clone方法以及深複製和淺複製
Java中處理基本資料型別(如:int , char , double等),都是採用按值傳遞的方式執行,除此之外的其他型別都是按照引用傳遞(傳遞的是一個物件的引用)的方式執行。物件在函式呼叫時和使用“=”賦值時都是引用傳遞。 Java中clone方法的作用是為了在現實程式
Java之sleep()方法與yield()方法的區別
1.執行緒睡眠:sleep()方法 sleep() 使當前執行緒(即呼叫該方法的執行緒)暫停執行一段時間,讓其他執行緒有機會繼續執行(不理會其他執行緒的優先順序),並進入阻塞狀態,但它並不釋放物件鎖。噹噹前執行緒呼叫sleep()方法進入阻塞狀態後,在
JAVA中clone方法詳解
為了理解java的clone,有必要先了解一些東西。java的型別,java的型別分為兩大類,一類為primitive,如int,另一類為引用型別,如String,Object等等。java引用型別的儲存,java的引用型別都是儲存在堆上的。 Java程式碼 public
Java之toString方法
如何實現 方法 info ack 接收 總結 java nds 被調用 在Java中所有的類都有一個共同的父類Object(默認繼承,不用加extends關鍵字),toString方法就是Object類的一個方法,用來返回該對象的字符串表示形式(個人總結:需要把該類轉換
java之構造方法建立JFrame
package test; import java.awt.*; import javax.swing.*; public class demo extends JFrame{ privat
java中clone 方法的作用
java中的資料型別分為:基礎資料型別(int、char、double等),非基礎型別(,map.class等)。 在處理基本資料型別時候,採用按值傳遞的方式(傳遞的是輸入引數的複製),其他型別的處理按引用傳遞(傳遞的是物件的一個引用),另外物件呼叫時是引用傳遞,在使用“=
Object物件之clone方法
克隆的目的:快速建立一個已有物件的副本。克隆的步驟:建立一個物件將原有物件的資料匯入到新建立的資料中1. Object的clone()原始碼簡介 /** * Creates and returns a copy of this {@code Object}. The default *
JavaSE入門學習23:Java面向對象之構造方法
ons 抽象類 什麽 ont 機會 語法 好的 error return 學了JavaSE面向對象這一部分,也該對構造方法做一個總結了。 一構造方法 在多數情況下,初始化一個對象的終於步驟是去調用這個對象的構造方法。構造
java設計模式之模板方法模式
java 設計模式宋丹丹姐的一個小品,說把大象放入冰箱分為幾步驟,三步、第一步:把冰箱門打開,第二步:把大象裝進去,第三步:把冰箱門關上。就是這樣的一個小品,可以說是其實簡化的一個模板方法。把雞蛋裝進冰箱分為幾步,同樣也是這個道理。模板方法模式概念:把一些共同的行為抽象出來,作為父類公共使用,一些具體的步驟
Java之線程,常用方法,線程同步,死鎖
時間 imp log 沖突 根據 oms adl 無法 誰的 1, 線程的概念 進程與線程 進程:每個進程都有獨立的代碼和數據空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1--n個線程。(進程是資源分配的最小單位) 線程:同一類線程共享代碼和數據空間,每個線
《JAVA與模式》之模板方法模式
cal php pri jsm vsm uft tmp throw tox 模板方法模式是類的行為模式。準備一個抽象類,將部分邏輯以具體方法以及具體構造函數的形式實現,然後聲明一些抽象方法來迫使子類實現剩余的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩余的邏輯
《JAVA與模式》之工廠方法模式
ktv bwt dex zoho ase lba dmg bps rpc 在閻宏博士的《JAVA與模式》一書中開頭是這樣描述工廠方法模式的: 工廠方法模式是類的創建模式,又叫做虛擬構造子(Virtual Constructor)模式或者多態性工廠(Polymorphic
Java之使用Integer類中的parseInt()方法將字符串轉換為基本數據類型
javaimport java.util.*; public class SystemInfo { public static void main(String[] args) { Properties sp = System.getProperties();