java 序列化和 hashcode、equals 方法重写
2016-12-02 16:46
387 查看
1.序列化是干什么的?
简单的来说就是为了保存各个对象在内存中的状态(也就是实例的变量,不是方法),并且可以把保存的对象状态读出来。虽然你可以用你自己的各种各样的方法来保存 object states,但是java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。2.什么情况下需要序列化
1. 当你想把内存中的对象状态保存到一个文件或者是数据中的时候; 2. 当你想用 socket 在网络中传输对象的时候; 3. 当你想通过 RMI 传输对象的时候;
3.当对一个对象进行序列化的时候发生了什么
在没有序列化前,每个保存在堆中的对象都有相应的状态(state),即实例变量(instance ariable)比如:Foo myFoo = new Foo(); myFoo.setWidth(37); myFoo.setHeight(70);
当通过下面的代码实例化后,myFoo 对象中的 width 和 height 都被保存到文件foo.ser当中了,这样以后可以把它从文件中读取出来,重新再堆中创建原来的对象。当然保存的时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等一遍恢复原来的对象。
FileOutputStream fs = new FileOutputStream("foo.ser"); ObjectOutputStream os = new ObjectOutputStream(fs); os.writeObject(myFoo);
序列化和反序列化的例子:
实体类:
package com.dada.foo; import java.io.Serializable; /** * 实现了 Serializable 接口 * 没有重写 hashCode和 equals方法 * @author Administrator * */ public class MyFoo1 implements Serializable { private int width; private int height; public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public MyFoo1(int width, int height) { super(); this.width = width; this.height = height; } }
测试类:
@Test public void testWriteAndReadbject() throws Exception { MyFoo1 myFoo = new MyFoo1(20, 30); // 把对象写到文件中 FileOutputStream fos = new FileOutputStream("D:\\myFoo.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(myFoo); // 读取对象信息 FileInputStream fis = new FileInputStream("D:\\myFoo.ser"); ObjectInputStream ois = new ObjectInputStream(fis); MyFoo1 myFoo1 = (MyFoo1) ois.readObject(); }
简而言之:序列化的作用就是为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制,效率之高,是其他解决方案无法比拟的
4.为什么序列化对象通常要重写 hashCode 和 equals方法
2个内容完全一样的对象,在我们“人”看来就是一样的对象,但是计算机不这么认为,为了保证对象在进行比较时候符合人们的思维习惯,所以我们需要重写这2个方法。在向 set 这种集合中添加对象的时候,set 要求对象都是不重复的,这个检查重复的过程,首先是检查对象的 hashCode() 值,如果这个值一致的话再去通过 equals 方法进行比较,如果 equals方法返回true,那么这个对象就不会被加入到 set 当中。
类:MyFoo
package com.dada.foo; /** * 没有实现 Serializable 接口 * @author Administrator * */ public class MyFoo { private int width; private int height; public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public MyFoo(int width, int height) { super(); this.width = width; this.height = height; } }
类:MyFoo1
package com.dada.foo; import java.io.Serializable; /** * 实现了 Serializable 接口 * 没有重写 hashCode和 equals方法 * @author Administrator * */ public class MyFoo1 implements Serializable { private int width; private int height; public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public MyFoo1(int width, int height) { super(); this.width = width; this.height = height; } }
类:MyFoo2
package com.dada.foo; import java.io.Serializable; /** * 1.实现了 Serializable 接口 * 2.重写了 hashCode、equals 方法 * @author Administrator * */ public class MyFoo2 implements Serializable { private Long id; private int width; private int height; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public MyFoo2(Long id, int width, int height) { super(); this.id = id; this.width = width; this.height = height; } @Override public int hashCode() { return id != null ? id.hashCode() : 0; } @Override public boolean equals(Object o) { // 比较引用 if(this == o) return true; // 比较类型 if(o == null || getClass() != o.getClass()) return false; // 比较内容,这里比较的是 id 值 MyFoo2 other = (MyFoo2) o; // 判断逻辑就是:三元运算符 的结果如果等于null 那么就返回 false // 首先确定当前 id 不等于 null,然后确定当前 id 不等于被比较的 id // 最后条件都满足了之后还是不等null,说明肯定不一致就返回 false 就可以了 if (id != null ? !id.equals(other.id) : other.id != null) return false; return true; } @Override public String toString() { return "MyFoo2{" + "id=" + id +","+ "width=" + width +","+ "height=" + height + "}"; } }
测试类:
package com.dada.foo; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashSet; import java.util.Set; import org.junit.Test; public class TestSerializable { /** * 1.实现了 Serializable 接口的类的对象的状态是可以被持久化的 * 2.没有实现这个接口的类是无法被实例化的 * 3.执行这个测试会报下名的报下面的错误 * java.io.NotSerializableException: com.dada.foo.MyFoo * @throws Exception */ @Test public void testWirteObject() throws Exception { // 把 MyFoo1 对象写入到文件 MyFoo1 myFoo1 = new MyFoo1(20, 30); FileOutputStream fos1 = new FileOutputStream("myFoo1.out"); ObjectOutputStream oos1 = new ObjectOutputStream(fos1); oos1.writeObject(myFoo1); oos1.close(); // 把 MyFoo 写入到文件 MyFoo myFoo = new MyFoo(10,20); FileOutputStream fos = new FileOutputStream("myFoo.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); // 这里就会报错,因为 MyFoo1 没有实现 Serializable 接口 // 没有实现实例化接口的对象是无法被写到文件里面去的 oos.writeObject(myFoo); } /** * 1.没有重写 hashcode 和 equals 方法的对象,在加入到 set 的过程中会被重复加入的 * 2.测试中 set 的size为:2 * @throws Exception */ @Test public void testWriteAndReadbject() throws Exception { MyFoo1 myFoo = new MyFoo1(20, 30); // 把对象写到文件中 FileOutputStream fos = new FileOutputStream("D:\\myFoo.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(myFoo); Set<MyFoo1> set = new HashSet<MyFoo1>(); set.add(myFoo); // 读取对象信息 FileInputStream fis = new FileInputStream("D:\\myFoo.out"); ObjectInputStream ois = new ObjectInputStream(fis); MyFoo1 myFoo1 = (MyFoo1) ois.readObject(); set.add(myFoo1); System.out.println(set.size()); } /** * 1.为了解决上面的问题,我们需要把对象 hashCode,equals方法重写 * 2.这样当逻辑上同样的对象被加入同一个set中的时候,set就会首先调用 hashCode 来比较两个对象是不是一样 * 3.如果 hashCode 都一样的话,就会调用对象的 equals 方法进行比较,如果这个也是一样的话就不会把它加入到 set 中去 * 4.重写了 hashCode 方法和 equals 方法之后 size 为 :1 * throws Exception */ @Test public void testHashCodeEquals() throws Exception { MyFoo2 myFoo2 = new MyFoo2(1l, 20, 30); System.out.println("被写入文件对象的 hasCode 值:" + myFoo2.hashCode()); System.out.println("toString :" + myFoo2); Set<MyFoo2> set = new HashSet<MyFoo2>(); set.add(myFoo2); // 把对象写到文件中 FileOutputStream fos = new FileOutputStream("D:\\myFoo2.out"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(myFoo2); // 读取对象信息 FileInputStream fis = new FileInputStream("D:\\myFoo2.out"); ObjectInputStream ois = new ObjectInputStream(fis); MyFoo2 myFoo21 = (MyFoo2) ois.readObject(); System.out.println("============================="); System.out.println("被读取文件对象的 hasCode 值:" + myFoo21.hashCode()); System.out.println("toString :" + myFoo2); System.out.println(myFoo2 == myFoo21); set.add(myFoo21); System.out.println(set.size()); } }
相关文章推荐
- java equals与hashCode 两个重要方法的重写
- JAVA中重写equals()方法为什么要重写hashcode()方法?
- Java重写equals方法时为什么要重写hashcode方法
- JAVA中重写equals()方法为什么要重写hashcode()方法说明
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)
- java中重写Object类的equals方法和Hashcode方法的注意事项
- JAVA中重写equals()方法为什么要重写hashcode()方法?
- JAVA类中的equals()方法和hashCode()方法的重写
- ID的生成策略(hibernate的id生成策略,主键类为什么需要实现序列化接口,同时还要重写hashCode()和equals()方法)
- 重写Java Object对象的hashCode和equals方法实现集合元素按内容判重
- Java中重写Object类的equals方法和hashcode方法的注意事项
- 类的高级运用、异常、集合、文件读写、序列化、重写equals和hashCode方法实例
- JAVA中重写equals()方法为什么要重写hashcode()方法?
- JAVA中重写equals()方法为什么要重写hashcode()方法?
- JAVA中重写equals()方法为什么要重写hashcode()方法说明
- JAVA中重写equals()方法为什么要重写hashcode()方法?
- JAVA中重写equals()方法为什么要重写hashcode()方法?
- Java中重写Object类的equals方法和 hashcode方法的注意事项
- java 重写HashCode和equals方法以及 HashMap集合 增 删 改 查
- JAVA中重写equals()方法为什么要重写hashcode()方法?