1.定义
java对象序列化机制允许实现了Serializable/Externalizable接口的java对象永久性地保存到计算机的磁盘中,或则允许java对象直接在网络中传输,摆脱平台的限制。反序列化即使将IO流中的字节序列转化为java对象。
2.原理
3.使用
序列化:
1)一个实现了Serializable接口的Java类
2)创建一个ObjectOutputSream对象
3)ObjectOutputSream是一个处理流,必须建立在其他节点流的基础上
ObjectOutputSream objectOutputSream=new ObjectOutputSream(new FileOutputStream(“obj.txt”));
Student student=new Student();
objectOutputSream. writeObject(student);
测试代码:调用ObjectOutputStream对象的writeObject()方法即可完成将一个java对象序列化为文件
public class SerializableTest { static Logger logger=Logger.getLogger("SerializableTest"); public static void main(String[] args){ try{ ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("student.txt")); Student student=new Student(); objectOutputStream.writeObject(student); } catch (FileNotFoundException e){ logger.warning("没找到文件"); } catch (IOException e){ logger.warning("序列化"+SerializableTest.class.getName()+"的对象失败"); } } }
创建一个ObjectInputStram对象反序列化:
调用ObjectInputStream对象的readObject()方法
测试代码:
public static Object readObj(FileInputStream fileInputStream) throws IOException, ClassNotFoundException{ ObjectInputStream objectInputStream=null; try{ objectInputStream=new ObjectInputStream(fileInputStream); } catch (IOException e){ logger.info("创建objectInputStream时失败"); } return objectInputStream.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException{ //SerializableTest.writeObj(); Student student=(Student)SerializableTest.readObj(new FileInputStream("student.txt")); System.out.println(student.toString()); }
4应用
什么情况下需要序列化?
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
相关注意事项 :
a)序列化时,只对对象的状态进行保存,而不管对象的方法;
b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
d)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:
1)安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
2)资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。
5对象引用的序列化
当一个对象中含有另一个对象的引用时。
假设现在有一个student对象和两个teacher对象,其中两个teacher对象都含有该student实例的引用,那么在序列化这三个对象时,会出现一个问题:student实例会被序列化三次,那么在反序列化这三个实例时,会实例化三个student对象,会造成这三个student对象不是同一个对象,这是不符合我们的最初要求的。
那么,怎么解决这个问题呢?
Java在实现对象引用的序列化时是这样做的:每一个被序列化到磁盘的对象都会有一个序列化编号,在序列化一个对象时,会通过该编号检查该对象是否已经被实例化过了。如果已经实例化过了,那么会返回一个序列化编号而不会重新序列化该对象。只有没有被序列化过的对象才会被序列化。
6解决同一个类的不同实例在序列化时序列字节文件因为同名被覆盖的问题
7如果序列化一个实例时不对序列化的文件的名字加以特殊处理,那么再次序列化同类实例时会出现序列字节文件因为同名被覆盖的问题
解决方案
1:在文件名后加哈希值做后缀
2.statement和prepareStatement的使用
区别在于prepareStatement是预编译语句,它会先将一个SQL语句编译好,在后面的使用中只需要向其传入参数即可。
如果对于一个经常出现的数据库操作,应该使用预编译SQL语句的方式,这种方式虽然在创建prepareStatement的消耗上大于statement,但是在后面的使用中不需要再次编译,因此可以提高性能。 但是对于只做少次的数据库操作,使用statement或许效率更高。