Java中的深克隆和浅克隆——Cloneable接口

一、没有使用克隆带来的问题

public class CloneTest

{

static Student s = new Student("aaa", 20);

// 直接赋值带来的问题

public static void noclone()

{

// 传的是引用的副本,改变了noCloneStudent也改变了s

Student noCloneStudent = new Student();

noCloneStudent = s;

noCloneStudent.setName("bbb");

noCloneStudent.setAge(21);

System.out.println(s);

System.out.print(noCloneStudent);

}

}

Student [name=bbb, age=21]

Student [name=bbb, age=21]

本意是设置noCloneStudent中的值,但把原来的对象s中的值也改变了。

二、浅克隆与深克隆

①浅克隆——若要克隆Student对象,只克隆他自身以及他包含的所有对象的引用地址。

②深克隆——克隆除自身以外所有的对象,包括自身所包含的所有对象实例。由具体的需求决定深克隆的层次(N层克隆)。

三、浅克隆

public class Student implements Cloneable

{

private String name;

private int age;

public Student()

{

super();

}

public Student(String name, int age)

{

super();

this.name = name;

this.age = age;

}

// 浅克隆

protected Object clone() throws CloneNotSupportedException

{

return super.clone();

}

public String toString()

{

return "Student [name=" + name + ", age=" + age + "]";

}

......

}

public class CloneTest

{

static Student s = new Student("aaa", 20);

// 浅克隆

public static void test0() throws Exception

{

Student ss = (Student) s.clone();

ss.setName("bbb");

ss.setAge(21);

System.out.println(s);

System.out.print(ss);

}

}

Student [name=aaa, age=20]

Student [name=bbb, age=21]

克隆的效果就达到了。

四、深克隆

public class TClass implements Cloneable

{

private Student stu;

private String name;

private List<String> courses = new ArrayList<String>();

public TClass()

{

super();

}

public TClass(Student stu, String name, List<String> courses)

{

super();

this.stu = stu;

this.name = name;

this.courses = courses;

}

// 深克隆

public Object clone() throws CloneNotSupportedException

{

TClass tea = (TClass) super.clone();

tea.stu = (Student) tea.stu.clone();

return tea;

}

public String toString()

{

return "TClass [stu=" + stu + ", name=" + name + ", courses=" + courses + "]";

}

......

}

// 深克隆

public static void test1() throws Exception

{

TClass t = new TClass();

t.setStu(s);

t.setName("张老师");

t.getCourses().add("JAVA");

t.getCourses().add("C#");

System.out.println(t);

TClass tt = (TClass) t.clone();

Student sss = (Student) s.clone();

sss.setName("bbb");

sss.setAge(21);

tt.setStu(sss);

tt.setName("李老师");

tt.getCourses().add("oracle");

tt.getCourses().add("mysql");

System.out.println(t);

System.out.println(tt);

}

TClass [stu=Student [name=aaa, age=20], name=张老师, courses=[JAVA, C#]]

TClass [stu=Student [name=aaa, age=20], name=张老师, courses=[JAVA, C#, oracle, mysql]]

TClass [stu=Student [name=bbb, age=21], name=李老师, courses=[JAVA, C#, oracle, mysql]]

动态数组还是保留了原来的引用,所以其数组没有达到拷贝的效果。

改造一下,让其中的数组有新的引用

public class TClass implements Cloneable

{

private Student stu;

private String name;

private List<String> courses = new ArrayList<String>();

public TClass()

{

super();

}

public TClass(Student stu, String name, List<String> courses)

{

super();

this.stu = stu;

this.name = name;

this.courses = courses;

}

// 深克隆(更深一层)

public Object clone() throws CloneNotSupportedException

{

TClass tea = (TClass) super.clone();

tea.stu = (Student) tea.stu.clone();

tea.courses = new ArrayList<String>(); // 指向不同引用

return tea;

}

public String toString()

{

return "TClass [stu=" + stu + ", name=" + name + ", courses=" + courses + "]";

}

......

}

TClass[stu=Student [name=aaa, age=20], name=张老师, courses=[Java, C#]]

TClass[stu=Student [name=bbb, age=21], name=李老师, courses=[oracle, mysql]]

再改造一下,希望动态数组既有了新的引用,又保留了原值

public class TClass3 implements Cloneable

{

private Student stu;

private String name;

private List<String> courses = new ArrayList<String>();

public TClass()

{

super();

}

public TClass(Student stu, String name, List<String> courses)

{

super();

this.stu = stu;

this.name = name;

this.courses = courses;

}

// 深克隆(更深一层)

public Object clone() throws CloneNotSupportedException

{

TClass tea = (TClass) super.clone();

tea.stu = (Student) tea.stu.clone();

// 指向不同引用

tea.courses = new ArrayList<String>();

// 又想保留原有的值

for (int i = 0; i < courses.size(); i++)

{

tea.courses.add(courses.get(i));

}

return tea;

}

public String toString()

{

return "TClass [stu=" + stu + ", name=" + name + ", courses=" + courses + "]";

}

......

}

Teacher [stu=Student [name=aaa, age=20], name=张老师, courses=[Java, C#]]

Teacher [stu=Student [name=bbb, age=21], name=李老师, courses=[Java, C#, oracle, spring]]

Java中的深克隆和浅克隆——Cloneable接口

时间: 2024-11-05 17:19:12

Java中的深克隆和浅克隆——Cloneable接口的相关文章

Java中的深克隆和浅克隆

为什么要克隆 首先思考一个问题, 为什么需要克隆对象? 直接new一个对象不行吗? 克隆的对象可能包含一些已经修改过的属性, 而new出来的对象的属性都还是初始化时候的值, 所以当需要一个新的对象来保存当前对象的"状态"时就要靠克隆了. 当然, 把对象的属性一个一个的赋值给新new的对象也是可以的, 但是这样一来麻烦不说, 二来, 我们通过源码查看 Object的clone方法是一个native方法(native方法是非Java语言实现的代码, 供Java程序调用, 要想访问比较底层的

java中并不是任意多个接口都可以实现多实现

interface A{ public abstract void show(); } interface B{ public abstract int show(); } public class Test implements A, B{ public void show(){ System.out.println("A show!"); } /* 只写 void show()出现的问题: Test不是抽象的, 并且未覆盖B中的抽象方法show(); */ public int s

java中,一个类实现某个接口,必须重写接口中的所有方法吗

不一定,关键要看子类是否是抽象类.如果子类是非抽象类,则必须实现接口中的所有方法: 如果子类是抽象类,则可以不实现接口中的所有方法,因为抽象类中允许有抽象方法的存在!1.抽象类定义抽象类往往用来表征对问题领域进行分析.设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象.通常在编程语句中用 abstract 修饰的类是抽象类.在C++中,含有纯虚拟函数的类称为抽象类,它不能生成对象:在java中,含有抽象方法的类称为抽象类,同样不能生成对象.抽象类是不完整的,它只能用作基类

java中的异步处理和Feature接口(一)

背景介绍想象这样一个场景:你可能希望为你的法国客户提供指定主题的热点报道.为实现这一功能,你需要向 谷歌或者Twitter的API请求所有语言中针对该主题最热门的评论,可能还需要依据你的内部算法 对它们的相关性进行排序.之后,你可能还需要使用谷歌的翻译服务把它们翻译成法语,甚至 利用谷歌地图服务定位出评论作者的位置信息,最终将所有这些信息聚集起来,呈现在你的网站上. 典型的“混聚”式应用 在这种“混聚”应用式的应用中,我们的应用可能会有以下两种需求: 由于我们调用的许多都是外部提供的接口,极有可

java 中调用支付宝支付功能的接口

支付宝接口: 申请支付宝接口服务: 1.https://fuwu.alipay.com/platform/doc.htm#c11   Java-JDK 1.5 SDK 2.https://cshall.alipay.com/enterprise/help_detail.htm?help_id=516349 java 调用jdk服务: 1.https://openhome.alipay.com/platform/document.htm#down 2.https://b.alipay.com/or

Java中的类继承机制、接口

1)声明一个Person类,有name(String类型).age(int类型).sex(char类型)属性,通过构造方法进行赋值.一个show方法,返回String类型,内容如下: 某某 男(女) 年龄 2)声明一个Student类,继承Person类,增加id(int,学号)属性,通过构造方法,利用super调用父类构造方法来进行变量赋值.Override父类的show方法,返回String类型,内容如下: 某某 男(女) 年龄 学号 (提示:利用super调用父类的show方法得到除学号部

java中利用继承类和Runnable接口实现多线程的区别

利用继承Thread类实现的多线程无法资源共享 如下程序 class MyThread extends Thread{ public MyThread(String name){ super(); this.name=name; } public void run(){ while(tickets==0?false:true) { tickets--; System.out.println(name+" just selt one ticket,only "+tickets+"

java中抽象类和接口的用法和区别

一.抽象类 1.抽象类 包含一个抽象方法的类就是抽象类 2.抽象方法 声明而未被实现的方法,抽象方法必须使用abstract关键词字声明 public abstract class People { //关键词abstract,声明该类为抽象类 public int age; public void Num() { } public abstract Name(); //声明该方法为抽象方法 } 3.抽象类被子类继承,子类(如果不是抽象类)必须重写抽象类中的所有抽象方法 4.抽象类不能被直接实例

关于java中任意对象强制转换为接口类型的问题

java中任意对象强转为接口类型都不会有编译错误 public class Apple implements Eatable{ public static void main(String args[]) { Drinkable drinkable = (Drinkable)new Apple(); } } interface Eatable{} interface Drinkable{} java中的类可以多实现接口,Java编译器无法判断该类是否实现了该接口所以不会有编译错误. 但是Java