1.直接赋值 (引用复制 ),此种复制方式比较常用。
诸如 A a = b a 是直接复制了b的引用 ,也就是说它俩指向的是同一个对象。 此时 a == b [ true ] 。
8f900a89c6347c561fdf2122f13be562.png
961ddebeb323a10fe0623af514929fc1.png
1 classA{2 privateString string3 A(){string = new String("original state")}4 public void set(String string) {this.string =string}5 public String get() {returnstring}6 }7
8 public classB{9 public static voidmain(String[] args) {10 //TODO 自动生成的方法存根
11 A a = newA()12 A b =a13 System.out.println(a ==b)14 a.set("state has changed")15 System.out.println(a ==b)16 }17 }
View Code
2.浅拷贝 ------- 复制当前对象的非静态字段【静态字段只在类加载的时候加载一次】,如果当前字段为 值类型 字段,那么直接复制该字段,如果是 引用类型 的,则对其复制引用。
所谓的值类型就是指Java中的8种基本类型,那么什么是值类型的复制呢?
举个例子 int A = 0int B = A那么这样B拷贝的是A指向的常量对象,而非A的引用,当A改变时,并不会影响B的指向。【Ps: A =1则B = 0 ,而非 1 , 这就是值类型的复制】
所谓的引用类型就是一些你自己构建的类和库中的一些类实例化出来的对象,引用复制又指的啥呢?
举个例子
class A {public int value = 0 } ====>A a = new A()A b = a =====> a.value = 1 那么 ==> b.value = 1; 因为它们指向的是同一个对象【复制的是引用】
8f900a89c6347c561fdf2122f13be562.png
961ddebeb323a10fe0623af514929fc1.png
1 class B implementsCloneable{2
3 privateC c4
5 privateString string 6 public B() {string = new String("Init string")c = newC()}7 public void set(String string) {this.string =string}8 public String get() {returnstring}9
10 //setC()方法中添加一句 c = new C() ,就变为深拷贝了,因为添加了 这句代码, 拷贝 引用类型时,就变成拷贝其对象,而不是引用了
11 public voidsetC(String string) {c.set(string)}12 public String getC() {returnc.get()}13
14
15 @Override16 publicObject clone() {17 B sCopy = null18 try{19 sCopy = (B)super.clone()20 }catch(Exception e) {21 e.printStackTrace()22 }23 returnsCopy24 }25 }26 public static voidmain(String[] args) {27 //TODO 自动生成的方法存根
28
29
30 B sCopyA = newB()31 B sCopyB =(B) sCopyA.clone()32
33 sCopyA.set("hava changed !")34 //sCopyA.string = hava changed ! ------- sCopyA.string = Init string35 //改变了 sCopyA 并没有改变 sCopyB。 因为 B.string 是一个值类型
36 System.out.println("sCopyA.string = "+ sCopyA.get()+" ------- sCopyA.string = "+sCopyB.get())37
38 sCopyB.setC("C have Changed !")39 //C.string = C have Changed ! ------- C.string = C have Changed !40 //改变了 sCopyA 同时也改变 sCopyB。因为 B.string 是一个引用类型
41 System.out.println("C.string = "+ sCopyA.getC()+" ------- C.string = "+sCopyB.getC())42 }
View Code
3.深拷贝 ------- 和浅拷贝的区别就在于,其不管字段类型是什么,统统的全给拷贝过去【即使相对与 非基本类型而言 拷贝的也是对象而不是引用 ,深拷贝之后将会产生2个对象 ,浅拷贝只是一个对象的2个引用而已(相当于1个人的2个名字)】。
我们只要在 2的基础上添加一行代码就行, 因为只要将 引用字段,也进行复制 ,就是深拷贝了。
附:1.clone()方法 需要覆写。 2.覆写clone()方法需要实现Cloneable 接口, 未实现的话会抛出异常。 3 .clone()是本地方法,其内部实现如下图。
2708f3cdcfe8a632a43a58352302c9b8.png
/*** 复制对象
*
* @param srcObj
* @return
*/
public static Object depthClone(Object srcObj) {
if (srcObj == null) {
return null
}
Object cloneObj = null
ByteArrayOutputStream out = null
ObjectOutputStream oo = null
ByteArrayInputStream in = null
ObjectInputStream oi = null
try {
out = new ByteArrayOutputStream()
oo = new ObjectOutputStream(out)
oo.writeObject(srcObj)
in = new ByteArrayInputStream(out.toByteArray())
oi = new ObjectInputStream(in)
cloneObj = oi.readObject()
} catch (IOException e) {
e.printStackTrace()
} catch (ClassNotFoundException e) {
e.printStackTrace()
} finally {
if (out != null) {
try {
out.close()
} catch (IOException ex) {
ex.printStackTrace()
}
}
if (oo != null) {
try {
oo.close()
} catch (IOException ex) {
ex.printStackTrace()
}
}
if (in != null) {
try {
in.close()
} catch (IOException ex) {
ex.printStackTrace()
}
}
if (oi != null) {
try {
oi.close()
} catch (IOException ex) {
ex.printStackTrace()
}
}
}
return cloneObj
}
使用Java的反射机制实现:为了能更好的区分,写成了两个类,可以运行下面的代码看看效果import java.lang.reflect.Field
import java.lang.reflect.Method
import java.util.ArrayList
import java.util.HashMap
import java.util.List
import java.util.Map
public class Test {
public static void main(String[] args) throws Exception {
Customer1 c1 = new Customer1()
c1.setName("c1")
List<String>list = new ArrayList<String>()
list.add("1")
list.add("2")
c1.setList(list)
Map<String,String>map = new HashMap<String, String>()
map.put("map1", "map1")
map.put("map2", "map2")
c1.setMap(map)
Customer2 c2 = new Customer2()
//
Class c = c1.getClass()
Class class2 = c2.getClass()
Field fields[] = c.getDeclaredFields()
for (int i = 0i <fields.lengthi++) {
Field field = fields[i]
String fieldName = field.getName()
String firstLetter = fieldName.substring(0, 1).toUpperCase()
String getMethodName = "get" + firstLetter + fieldName.substring(1)
String setMethodName = "set" + firstLetter + fieldName.substring(1)
Method getMethod = c.getMethod(getMethodName, new Class[] {})
Method setMethod = class2.getMethod(setMethodName,
new Class[] { field.getType() })
Object value = getMethod.invoke(c1, new Object[] {})
setMethod.invoke(c2, new Object[] { value })
}
System.out.println(c2.getName())
System.out.println(c2.getList())
System.out.println(c2.getMap())
}
}
class Customer1 {
private String name
private List<String>list
private Map<String, String>map
public String getName() {
return name
}
public void setName(String name) {
this.name = name
}
public List<String>getList() {
return list
}
public void setList(List<String>list) {
this.list = list
}
public Map<String, String>getMap() {
return map
}
public void setMap(Map<String, String>map) {
this.map = map
}
}
class Customer2 {
private String name
private List<String>list
private Map<String, String>map
public String getName() {
return name
}
public void setName(String name) {
this.name = name
}
public List<String>getList() {
return list
}
public void setList(List<String>list) {
this.list = list
}
public Map<String, String>getMap() {
return map
}
public void setMap(Map<String, String>map) {
this.map = map
}
}