Java中的对象克隆
来源:互联网 发布:一掌经六道轮回的算法 编辑:程序博客网 时间:2024/06/06 03:44
在 Java 语言中,我们说两个对象是否相等通常有两层含义:
1。对象的内容是否相等,通常使用到对象的 equals(Object o) 函数;
2。引用的地址是否相同,使用运算符 == 比较即可。
当两个对象通过赋值符号 = 赋值时,表明这两个对象指向了内存中同一个地址,所以改变其中一个对象的内容,也就间接地改变了另一个对象的内容。有时候,我们需要从一个已经存在的对象重新拷贝一份出来,并且不仅这两个对象内容相等,在内存中存在两个独立的存储地址,互不影响,这时,就需要用到 Java 中的克隆机制。
Cloneable
通过 Cloneable 接口可以很轻松地实现 Java 对象的克隆,只需要 implements Cloneable 并实现 Object 的 clone() 方法即可。注意这里对象实现的是 Object 类的 clone() 方法,因为 Cloneable 是一个空接口:
public interface Cloneable {}
从源码注释中可以看出,需要实现 Object 类中的 clone() 方法(注意:clone() 函数是一个 native 方法,同时抛出了一个异常):
protected native Object clone() throws CloneNotSupportedException;
测试代码如下(注意:我们在 User 对象中重写了 equals() 函数):
public class User implements Cloneable { private String username; private String password; public User(String username, String password) { super(); this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } @Override public boolean equals(Object obj) { User user = (User)obj; if(username.equals(user.username) && password.equals(user.password)) { return true; } return false; } public static void main(String[] args) throws CloneNotSupportedException { User userOne , userTwo, userThree; userOne = new User("username", "password"); userTwo = userOne; userThree = (User) userOne.clone(); System.out.println(userTwo == userOne); //true System.out.println(userTwo.equals(userOne));//true System.out.println(userThree == userOne);//false System.out.println(userThree.equals(userOne));//true }}
测试结果显示,通过 clone() 函数,我们成功地从 userOne 对象中克隆出了一份独立的 userThree 对象。
浅克隆与深克隆
谈此之前,我们先看一个例子,定义一个名为 Company 的类,并添加一个类型为 User 的成员变量:
public class Company implements Cloneable { private User user; private String address; public Company(User user, String address) { super(); this.user = user; this.address = address; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }// protected Object clone() throws CloneNotSupportedException {// Company company = (Company) super.clone();// company.user = (User) company.getUser().clone();// return company;// } @Override public boolean equals(Object obj) { Company company = (Company)obj; if(user.equals(company.getUser()) && address.equals(company.getAddress())) { return true; } return false; } public static void main(String[] args) throws CloneNotSupportedException { Company companyOne, companyTwo, companyThree; companyOne = new Company(new User("username", "password"), "上海市普陀区"); companyTwo = companyOne; companyThree = (Company)companyOne.clone(); System.out.println(companyOne == companyTwo); System.out.println(companyOne.equals(companyTwo)); System.out.println(companyOne == companyThree); System.out.println(companyOne.equals(companyThree)); System.out.println(companyThree.getUser() == companyOne.getUser()); System.out.println(companyThree.getUser().equals(companyOne.getUser())); }}
问题来了,companyThree 与 companyOne 中的 User 是同一个对象!也就是说 companyThree 只是克隆了 companyOne 的基本数据类型的数据,而对于引用类型的数据没有进行深度的克隆。也就是俗称的浅克隆。
浅克隆:顾名思义,就是很表层的克隆,只克隆对象自身的引用地址;
深克隆:也称“N层克隆”,克隆对象自身以及对象所包含的引用类型对象的引用地址。
这里需要注意的是,对于基本数据类型(primitive)和使用常量池方式创建的String 类型,都会针对原值克隆,所以不存在引用地址一说。当然不包括他们对应的包装类。
所以使用深克隆就可以解决上述 Company 对象克隆过后两个 user 对象的引用地址相同的问题。我们修改一下 Company 类的 clone() 函数:
protected Object clone() throws CloneNotSupportedException { Company company = (Company) super.clone(); company.user = (User) company.getUser().clone(); return company; }
再运行测试代码,就能得到 companyThree.getUser()==companyOne.getUser() 为 false 的结果了。
Serializable实现
通过上述介绍,我们知道,实现一个对象的克隆,需要如下几步:
1。对象所在的类实现 Cloneable 接口;
2。重写 clone() 函数,如果包涵引用类型的成员变量,需要使用深克隆。
如果对象不包含引用类型成员或者数量少的话,使用 Cloneable 接口还能接受,但当对象包含多个引用类型的成员,同时这些成员又包含了引用类型的成员,那层层克隆岂不是相当繁琐,并且维护不便?所以,这里介绍一种更加方便的实现方式,使用 ObjectOutputStream 和 ObjectOutputStream 来实现对象的序列化和反序列化
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class People implements Serializable { private String name; private int age; public People() { this.name = "wangwenhao"; this.age = 26; } 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; } public static void main(String[] args) throws IOException, ClassNotFoundException { People people = new People(); ObjectOutputStream oos = null; ObjectInputStream ois = null; FileOutputStream fos = new FileOutputStream("people.out"); oos = new ObjectOutputStream(fos); oos.writeObject(people); oos.close(); People anotherPeople = null; FileInputStream fis = new FileInputStream("people.out"); ois = new ObjectInputStream(fis); anotherPeople = (People) ois.readObject(); System.out.println("name: " + anotherPeople.getName() + " " + " age: " + anotherPeople.getAge()); ois.close(); }}
序列化一组对象,因为数组属于引用数据类型, 所以可以直接使用Object类型接收。下面是代码演示:
import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.OutputStream;import java.io.Serializable;class Person implements Serializable { private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; }}public class SerDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { Person per[] = {new Person("张三", 30), new Person("李四", 31), new Person("王五", 32)}; ser(per); Object o[] = dser(); for(int i = 0; i < o.length; i++) { Person p = (Person)o[i]; System.out.println(p); } } public static void ser(Object obj[]) throws IOException { File f = new File("D:" + File.separator + "test.txt"); OutputStream out = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(obj); oos.close(); } public static Object[] dser() throws IOException, ClassNotFoundException { File f = new File("D:" + File.separator + "test.txt"); InputStream input = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(input); Object obj[] = (Object[]) ois.readObject(); ois.close(); return obj; }}
参考:http://www.tuicool.com/articles/rYbA3y
- java中的对象克隆
- Java中的对象克隆
- Java中的对象克隆
- 详解Java中的对象克隆
- java克隆对象
- java 中克隆对象
- 浅谈java 对象克隆
- java对象的克隆
- java对象克隆clone
- java 对象 克隆 clone
- Java clone()克隆对象
- java对象的克隆
- JAVA 对象克隆clone
- java对象的克隆
- java 对象的克隆
- java对象克隆简介
- 模拟Java对象克隆
- Java克隆对象
- python+selenium高级教程
- 深度学习(08)_RNN-LSTM循环神经网络-03-Tensorflow进阶实现
- 关于 jquery bind()方法中不能绑定hover事件
- 非常有用的研究linux tcp的资料
- 怎么从remote端(远程服务器)拉取(checkout)文件
- Java中的对象克隆
- 关于static静态变量的几个问题
- Leetcode 239. Sliding Window Maximum
- JSP基础知识(9大内置对象)及常用API
- Codeforces 313D Ilya and Roads【Dp+思维】
- Springmvc第二讲学习笔记,文件上传
- SaltStack-02Haproxy以及Keepalived配置
- 机器学习:决策树算法
- Win10高分屏软件界面字体模糊问题解决