转载

Java如何实现深拷贝

protected 域(或方法)微妙的规则

protected 域(或方法)对本包内的所有类可见(当然包括子类),那么,子类可以获得访超类受保护域(或方法)的权利,但是,若子类和超类不在同一个包下,就不能访问超类对象的这个受保护域(或方法)。也就是说,不在一个包下,子类中不能通过一个父类对象的引用来获得父类受保护的域(或方法),测试如下。

package protect2;

public class P{

protected int a;

publicP(){}

publicP(int a){

this.a = a;

}

protectedvoidfun(){

System.out.println("父类protected方法");

}

}package protect2;

public class ProtectedTest {

public String s;

publicProtectedTest(String s) {

this.s = s;

}

P ap = new P(10);

voidfoo() {

ap.fun();

System.out.println("ap.a " + ap.a);

}

publicstaticvoidmain(String[] args) {

ProtectedTest test = new ProtectedTest("abcdef");

test.foo();

System.out.println(test.s);

}

}package protect;

import protect2.P;

class C extends P{

public int b;

publicC(int a,int b){

super(a);

this.b = b;

}

publicvoidafun(){

P pp = new P(10);

System.out.println("C.a= " + a);

System.out.println("P.a= " + pp.a);//ERROR:The field P.a is not visible

pp.fun(); //ERROR:The method fun() from the type P is not visible

}

--------------------------------------------------------------------------------

浅拷贝与深拷贝

Object类对自己的具体子类的域一无所知,Object类的clone方法只是将各个域进行拷贝。数值或基本类型不会出现问题,但是,如果在对象中包含了引用对象,这些对象的内容没有被自我复制,拷贝的结果也即是原始对象和拷贝对象引用着同一个引用对象(一般地,动词“引用”可理解为“管理”,就是指向同一内存)。

浅拷贝满足:

x.clone() != x为 true,

x.clone().getClass() == x.getClass()为true,

((x.clone().field1 ) == (x. field1))&& … &&((x.clone().fieldN )==(x. fieldN))也为 true 。

如果原始对象与浅拷贝对象共同引用(管理、指向)的引用对象是不可变的,将不会产生任何问题,如,引用对象是String类对象;或引用对象在其生命周期不会发生变化,具体来说,管理它的类中没有更改它的方法,也没有返回对它引用的方法(分享其管理权的方法)。

如果原始对象管理的引用对象是可变的,就必须需重新定义clone方法,来实现深层次的拷贝。要对涉及的每一个类,判断以下两点:

默认的clone方法是否满足需求。

默认的clone方法是否能通过调用可变引用对象的clone方法得到解决。

对涉及的每一个类,深拷贝要满足:

x.clone() != x为 true,

x.clone().getClass() == x.getClass()为true,

x.clone().equals(x)也为 true ,当然equals方法是如此重写过的。 https://www.linuxidc.com/Linux/2018-04/151899.htm

Object类中的clone方法被声明为protected,防止出现文章开头所提到的,子类和超类不在同一个包下的情况,要声明clone为public,来实现深拷贝:

import java.util.Date;

public class EqualsT {

publicstaticvoidmain(String[] args) throws CloneNotSupportedException {

Date hireDay = new Date();

Employee e1 = new Employee("Tommy", 10, "9998", hireDay);

Employee e2 = new Employee("Tommy", 10, "9998", hireDay);

System.out.println(e1.equals(e2));

System.out.println(e1 == e2);

Employee e3 = (Employee) e1.clone();

System.out.println(e1.equals(e3));

}

}

//Cloneable为标记接口,接口内没有方法。

class Employee implements Cloneable {

String name;

int age;

String salary;

Date hireDay;

publicEmployee(String name, int age, String salary, Date hireDay) {

super();

this.name = name;

this.age = age;

this.salary = salary;

this.hireDay = hireDay;

}

@Override

publicbooleanequals(Object otherObject) {

if (this == otherObject)

return true;

if (otherObject == null)

return false;

if (!(otherObject instanceof Employee))

return false;

Employee other = (Employee) otherObject;

return name.equals(other.name) && age == other.age && salary.equals(other.salary)

&& hireDay.equals(other.hireDay);

}

@Override

protected Object clone() throws CloneNotSupportedException {

// call Object.clone()

Employee cloned = (Employee) super.clone();

// call mutable fields

cloned.hireDay = (Date) hireDay.clone();

return cloned;

}

}

Output:

true

false

true

--------------------------------------------------------------------------------

// JDK中Date类的克隆方法

public Object clone() {

Date d = null;

try {

d = (Date)super.clone();

if (cdate != null) {

d.cdate = (BaseCalendar.Date) cdate.clone();

}

} catch (CloneNotSupportedException e) {} // Won't happen

return d;

}

本文永久更新链接地址: https://www.linuxidc.com/Linux/2018-04/151898.htm

原文  https://www.linuxidc.com/Linux/2018-04/151898.htm
正文到此结束
Loading...