JavaBean 持久化

【0】README

0.1)本文文字描述转自 core java volume 2,旨在学习  JavaBean 持久化 的基础知识;

0.2)本文所有源代码荔枝均为原创;

0.3) for complete souce code, please visit  https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter8

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

【1】JavaBean 持久化

1)JavaBena持久化定义: 用JavaBean的属性来将 bean 存储到流中, 并在之后的某个时刻,或者在另一个虚拟机中再将它们读回来;(javabean持久化定义)
2)JavaBean持久化与对象序列化的区别: JavaBean 持久化适合于长期存储;
3)problem+solution:
3.1)problem:序列化不适合长期存储;
3.2)solution:人们发明了长期存储机制——JavaBean持久化技术。
4)JavaBean持久化背后的思想:
4.1)对象序列化:假设你想将一个 JFrame 对象保存到一个文件中,以便以后可以读取。如果看一看JFrame 的源码会发现它有几十个实例域。如果该类被序列化,那么所有这些域的值都需要被写下来。
4.1.1)看看窗体(JFrame)是如何构造的:
JFrame frame = new JFrame();
frame.setTitle("my app");
frame.setVisible(true);
默认的无参构造器会初始化所有的实例域,然后由你设置一两个属性。然而, 如果该类被序列化,那么所有这些域的值都需要被写下来。(干货——序列化存储类的缺点是太冗余了,因为它要把所有域都保存下来)
4.2)如果用JavaBean持久化来保存的话,会产生如下XML语句:
<object class="javax.swing.JFrame"><void property="title"><string>my app</string></void><void property="visible"><boolean>true</boolean></void>
</object>
4.2.1)当该对象被读回的时候,只需要加载上述XML文件;
Attention) JavaBean持久化只会保存那些与默认值不同的属性。这个过程叫做——消除冗余;(干货——消除冗余定义)
5)XMLEncoder + XMLDecoder:
5.1)要将对象保存为流,需要使用 XMLEncoder:
XMLEncoder out = new XMLEncoder(new FileOutputStream(...));
out.writeObject();
out.close();
5.2)从文件中读取对象,需要使用 XMLDecoder:
XMLDecoder in = new XMLDecoder(new FileInputStream(...));
JFrame frame = (JFrame)in.readObject();
in.close();
package com.corejava.chapter8;public class Hello
{private String msg = "hello";private String speaker = "xiaotang";public String getMsg(){return msg;}public void setMsg(String msg){this.msg = msg;}public String getSpeaker(){return speaker;}public void setSpeaker(String speaker){this.speaker = speaker;}
}
package com.corejava.chapter8;import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;public class PersistentTest
{public static void main(String[] args){XMLEncoder e = null;// 持久化 java类到 XMLtry{e = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("com/corejava/chapter8/persistent.xml")));} catch (Exception ex){ex.printStackTrace();}Hello hello = new Hello();hello.setMsg("this is a test");hello.setSpeaker("persistent tang");e.writeObject(hello);e.close();// 持久化处理结束System.out.println("write Sucess");// 读取持久化对象XMLDecoder d = null;try{d = new XMLDecoder(new BufferedInputStream(new FileInputStream("com/corejava/chapter8/persistent.xml")));} catch (Exception f){f.printStackTrace();}Object result = d.readObject();Hello test = (Hello) result;System.out.println(test.getMsg() + test.getSpeaker());// 读取持久化对象结束}
}
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_60" class="java.beans.XMLDecoder"><object class="com.corejava.chapter8.Hello"><void property="msg"><string>this is a test</string></void><void property="speaker"><string>persistent tang</string></void></object>
</java>



【2】 JavaBean持久化可用于任何数据
1)XMLEncoder 内置了对下列类型的支持:

null;

所有基本类型及其包装器类型;

枚举;(从 Java SE6 开始)

String;

数组;

集合与映射表;

反射类型 Class, Field, Method 和 Proxy;

AWT类型.....

AWT 和 Swing 构建, 边界,布局管理器和模型;

事件处理器;


 【3】编写一个持久化代理(Persistence Delegate) 来构造对象
2.1)problem+solution:
2.1.1)problem:  如果可以通过属性得到每个对象的状态,那么使用 JavaBean持久化就是小菜一碟。但是,在真实的程序中,总有些类无法这样工作。如一个没有默认的无参构造器的Employee,它没有 setName, setSalary, setHireDay方法;
2.1.2)solution:要克服这个问题,可以定义一个持久化代理,该代理负责生成对象的XML 编码机制:(干货——引入持久化代理)
2.2)Employee类的持久化代理覆写了 instantiate 方法,以生成一个构造对象的表达式: 
PersistenceDelegate delegate = new PersistenceDelegate(){protected Expression instantiate(Object oldInstance, Encoder out){Employee e = (Employee) oldInstance;GregorianCalendar c = new GregorianCalendar();c.setTime(e.getHireDay());return new Expression(oldInstance, Employee.class, "new", new Object[] {e.getName(), e.getSalary(), c.get(Calendar.YEAR), c.get(Calendar.MONTH),c.get(Calendar.DATE) });}};
对以上代码的分析(Analysis): 要重新生成oldInstance, 可以调用 Employee.class 对象上的new 方法(也就是构造器), 并提供指定的参数。 
3)安装持久化代理有两种选择:
3.1)一种是将其与某个具体的 XMLWriter 相关联:
out.setPersistenceDelegate(Employee.class, delegate);
3.2)或者,可以设置 Beaninfo 的 bena 描述符的 persistenceDelegate 属性:
BeanInfo info = Introspector.getBeanInfo(GregorianCalendar.class);
info.getBeanDescriptor().setValue("persistenceDelegate", delegate);
3.3)一旦安装了代理, 就可以保存Employee 对象了,如:
Object myData = new Employee("harry hacker", 50000, 1989, 10, 1);
4) 持久化代理构造对象的荔枝

package com.corejava.chapter8;import java.beans.DefaultPersistenceDelegate;
import java.beans.Encoder;
import java.beans.Expression;
import java.beans.PersistenceDelegate;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;public class PersistentDelegateTest
{public static void main(String[] args){// 持久化代理对象PersistenceDelegate delegate = new DefaultPersistenceDelegate(){protected Expression instantiate(Object oldInstance, Encoder out){Employee e = (Employee) oldInstance;return new Expression(oldInstance, Employee.class, "new", new Object[]{e.getName(),e.getSalary(),e.getAge()});}};XMLEncoder out = null;// 持久化 java类到 XMLtry{out = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("com/corejava/chapter8/persistent_delegate.xml")));} catch (Exception ex){ex.printStackTrace();}// 安装持久化代理对象out.setPersistenceDelegate(Employee.class, delegate);Employee employee = new Employee("xiao tang", 110, 25);out.writeObject(employee);out.close();// 持久化处理结束System.out.println("write Sucess");}
}
package com.corejava.chapter8;// <span style="color:#ff0000;"><strong>无设置器(setXXX方法),也没有默认构造器</strong></span>
public class Employee
{private String name;private double salary;private int age;public Employee(String name, double salary, int age){this.name = name;this.salary = salary;this.age = age;}public String getName(){return name;}public double getSalary(){return salary;}public int getAge(){return age;}
}
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_60" class="java.beans.XMLDecoder"><object class="com.corejava.chapter8.Employee"><string>xiao tang</string><double>110.0</double><int>25</int></object>
</java>

【4】由属性构造对象
4.1)如果构造器所需的参数都可以通过访问 oldInstance 的属性获得, 那你就不必自己编写 instantiate 方法了。 你可以直接构造一个  DefaultPersistenceDelegate, 然后提供属性的名字即可。
4.2)看个荔枝:下面的语句为 Rectangle2D.Double 类设置了持久化代理:
out.setPersistenceDelegate(Rectangle2D.Double.class, new DefaultPersistenceDelegate(new String[]{"x", "y", "width", "height"}));
对上述代码的分析(Analysis):
A1)它告诉编译器: “要编码一个 Rectangle2D.Double 对象, 就要取得它的 x, y, width 和 height属性”, 并且用它们来调用构造器。其结果会产生包含如下元素的输出:
<object class="java.awt.geom.Rectangle2DDouble"><double>5.0</double><double>10.0</double><double>20.0</double><double>30.0</double>
</object>
5)使用@ConstructorProperties注解构造器:
5.1)看个荔枝: 假设Employee 类有一个接收3个参数的构造器,我们对其进行注解:  
@ConstructorProperties({"name","salary","age"})
public Employee(String name, double salary, int age)
对上述代码的分析(Analysis):
A1) 这可以告诉编码器去调用 getName, getSalary  和 getHireDay 这三个属性获取方法, 并将得到的值写入 object 表达式;
A2) @ConstructorProperties 注解是在 Java SE6 中引入的,因此只在 java 管理扩展(JMX) API中得到了应用;
public class DefaultPersistentDelegateTest
{public static void main(String[] args){XMLEncoder out = null;// 持久化 java类到 XMLtry{out = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("com/corejava/chapter8/default_persistent_delegate.xml")));} catch (Exception ex){ex.printStackTrace();}// 安装持久化代理对象// 它告诉编译器: “要编码一个 Employee 对象, // 就要取得它的 name, salary, age 属性”, 并且用它们来调用构造器。out.setPersistenceDelegate(Employee.class, new DefaultPersistenceDelegate(new String[]{"name","salary","age"}));Employee employee = new Employee("default xiao tang", 110, 25);out.writeObject(employee);out.close();// 持久化处理结束System.out.println("DefaultPersistentDelegateTest write Sucess");}
}

---------------------------------------------------------------------------------------------------------
【5】 使用工厂方法构造对象
5.1)
有时,你需要保存那些通过工厂方法获得的对象,而不是通过构造器产生的对象。
5.2)看个荔枝: 思考 你是如何得到一个 InetAddress对象的:
byte[] bytes = new byte[] {127, 0, 0, 1};
InetAddress address = InetAddress.getByAddress(bytes);
5.3) PersistenceDelegate 的 instantiate 方法会产生对工厂方法的一次调用:
protected Expression instantiate(Object oldInstance, Encoder out)
{
return new Expression(oldInstance, InetAddress.class, "getByAddress", new Object[] {((InetAddress)oldInstance).getAddress(); });
}
5.4) 下面是一个输出样例:
<object class="java.net.Inet4Address" method="getByAddress">
<array class="byte" length="4">
<void index="0">
<byte>127</byte>
</void>
<void index="3">
<byte>1</byte>
</void>
</array>
</object>

------------------------------------------------------------------------------------------------
【6】构造后的工作
6.1)problem+solution:
6.1.1)problem:
某些类的状态是通过调用 非属性设置方法来建立的,即 非 setXXX方法;
6.1.2)solution: 你可以通过覆写 DefaultPersistenceDelegate 的 initialize 方法来处理这种状况。initialize 方法会在 instantiate 方法之后调用, 在其中你可以生成将被 记录在bean存档文件中的 语句序列;
6.2)看个荔枝: 为了重新生成一个 BitSet 对象,你要设置原对象中存在的所有位。下面的 initialize 方法生成了必要的语句:
protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) 
{ 
super.initialize(type, oldInstance, newInstance, out);
BitSet bs = (BitSet) oldInstance;
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
out.writeStatement(new Statement(bs, "set", new Object[] { i, i + 1, true }));
}
6.2.1)输出样例如下所示:
<object class="java.util.BitSet">
<void method="set">
<int>1</int>
<int>2</int>
<boolean>true</boolean>
</void>
<void method="set">
<int>4</int>
<int>5</int>
<boolean>true</boolean>
</void>
</object>
Attention) 编写 new Statement(bs, "set", new Object[]{i}) 会更加有意义, 不过,那样的话, XMLWriter 会使用一个空的名字来设置属性, 而这样的语句不是很直观;
------------------------------------------------------------------------------------------------
【7】 瞬态属性
7.1)problem+solution:
7.1.1)problem:
偶尔, 类中会包含能够被 XMLDecoder 发现的带有 getXXX 和 setXXX的属性, 但是 你不希望在存档文件中包含该属性的值;
7.1.2)solution:为了禁止某个属性被存档, 可以在属性描述符中将 它标记为 transient;(干货——引入transient属性标记)
7.2)看个荔枝:
下面的语句吧 DamageReporter 类的 removeMode属性标记为 瞬时的;
BeanInfo info = Introspector.getBeanInfo(DamageReport.class);
for(PropertyDescriptor desc : info.getPropertyDescriptors())
if(desc.getName().equals("removeMode"))
desc.setValue("transient", Boolean.TRUE);
JavaBean 持久化的存档的总结(Conclusion):
C1)
适合长期存储的;
C2)小而且快的;
C3)易于生成的;
C4)易于人们进行编辑的;
C5)是标准java 的一部分;  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

apache kafka_Apache Kafka消费者再平衡

apache kafka消费者重新平衡决定哪个消费者负责某个主题的所有可用分区的哪个子集。 例如&#xff0c;您可能有一个包含20个分区和10个使用者的主题。 在重新平衡结束时&#xff0c;您可能希望每个使用者都从2个分区中读取数据。 如果关闭了这些使用者中的10个&#xff0c;则可…

Java 注解总结

一、注解定义 注解早在J2SE1.5就被引入到Java中&#xff0c;主要提供一种机制&#xff0c;这种机制允许程序员在编写代码的同时可以直接编写元数据。 二、元注解 Target 说明了被修饰的注解的应用范围&#xff0c;也就是被修饰的注解可以用来注解哪些程序元…

编译原理三大经典书籍(龙书 虎书 鲸书)

以下内容转自&#xff1a; http://blog.csdn.net/skymingst/article/details/7436892 1、龙书&#xff08;Dragon book&#xff09; 英文名&#xff1a;Compilers: Principles,Techniques,and Tools 作者&#xff1a;Alfred V.Aho,Ravi Sethi,Jeffrey D.Ullman 中文名&…

两个时间之间是多少小时_那是两个小时我不会回来

两个时间之间是多少小时正如我之前关于linting主题所说的 &#xff0c;花时间修改代码的好处很有限&#xff0c;因为自动工具告诉您这样做。 更糟糕的是&#xff0c;这些工具并非万无一失。 例如&#xff0c;我们一直在针对完美无害的try-with-resources构造周围的SpotBugs警告…

java的类载入器

【0】README 0.1&#xff09;本文文字转自&#xff1a; 深入剖析tomcat&#xff0c; 旨在 理解 jvm 的类载入器&#xff1b; 【1】 jvm的类载入器相关 1&#xff09;jvm 使用了3种类载入器来载入所需要的类&#xff1a;分别是引导类载入器&#xff08;bootstrap class load…

Java 代理总结

一、代理 为其他对象提供一种代理以便控制对这个对象的访问。 &#xff08;1&#xff09;静态代理 &#xff08;2&#xff09;动态代理 1&#xff09;JDK自带的动态代理 2&#xff09;javaassist字节码操作库实现 3&#xff09;CGLIB 4&#xff09; ASM&#xff08;底层…

分解因数 递归_递归分解WAR文件

分解因数 递归抽象 是否曾经需要分解WAR文件以及分解WAR文件中的所有JAR文件&#xff1f; 是的&#xff0c;我也是&#xff01; 我写了ferris-war-exploder来爆炸&#xff1a; 一个JAR文件 一个WAR文件&#xff0c;它找到的每个JAR文件也会爆炸。 包含每个JAR文件&#xff…

jvm(2)-java内存区域

【0】README 0.1&#xff09;本文转自 深入理解jvm&#xff0c; 旨在学习 java内存区域 的基础知识&#xff1b; 【1】运行时数据区域 1&#xff09;jvm 所管理的内存将会包括以下几个运行时数据区域 1.1&#xff09;方法区&#xff1b;&#xff08;线程共享&#xff09; 1.2&…

Java Socket编程总结

一、网络API InetAddress     用于标识网络上的硬件资源&#xff0c;主要是IP地址 URL         统一资源定位符&#xff0c;通过URL可以直接读取或写入网络上的数据Sockets      使用TCP协议实现的网络通信Socket相关的类Datagram     使用UDP协议&am…

java插入排序_Java程序要插入排序

java插入排序Java程序插入示例的排序。 显示了示例仿真以及时间复杂度。 插入排序是一种简单的排序算法&#xff0c;可以一次构建一个最终的排序数组&#xff08;或列表&#xff09;。 它比冒泡排序有效得多&#xff0c;并且在大型列表上的效率比快速排序 &#xff0c;堆排序或…

jvm(2)-JVM内存的设置(解决eclipse下out of memory问题)

【0】README 0.1&#xff09;本文转自&#xff1a; http://blog.csdn.net/sjf0115/article/details/8889201 一、JVM内存的设置的原理 默认的java虚拟机的大小比较小&#xff0c;在对大数据进行处理时java就会报错&#xff1a;java.lang.OutOfMemoryError。 设置jvm内存的方…

Java Servlet总结

一、Servlet简介 Servlet&#xff08;Server Applet&#xff09;是Java Servlet的简称&#xff0c;称为小服务程序或服务连接器&#xff0c;用Java编写的服务器端程序&#xff0c;主要功能在于交互式地浏览和修改数据&#xff0c;生成动态Web内容。狭义的Servlet是指Java语言实…

java oca_OCA第1部分中的Java难题

java oca我在业余时间正在阅读Mala Gupta的Oracle认证Java SE程序员助理书&#xff0c;我对所学到的一些新知识感到惊讶。 有时候他们真的没有道理&#xff0c;有时候他们说得通&#xff0c;但真的让人惊讶。 因此&#xff0c;在本系列文章中&#xff0c;我想将它们共享为“ Ja…

jvm(1)-走进java

【0】README0.1&#xff09;本文转自 深入理解 jvm&#xff0c;旨在了解 java 体系结构&#xff1b;【1】java技术体系1&#xff09; Sun 官方所定义的java 技术系统包括以下几个组成部分&#xff1a; java 程序设计语言&#xff1b;各种硬件平台上的java 虚拟机&#xff1b;Cl…

Java 高并发下的实践

一、使用的技术HashMap ConcurrentHashMap Lock ReadWriteLock synchronized 二、一百万并发下的组合 ConcurrentLockMap /** To change this license header, choose License Headers in Project Properties.* To change this template file, choose Tools | Templates* …

java oca_OCA第2部分中的Java难题

java oca欢迎使用OCA的Java Puzzlers的第二部分。 在这一部分中&#xff0c;我们将看到一个有趣的案例&#xff0c;涉及Java 7附带的数字文字中的下划线分隔符。 在下面的类中&#xff0c;您可以在十进制文字中看到分隔符下划线。 还请注意&#xff0c;该类现在可以正常编译。…

jvm(2)-OutOfMemoryError 异常(内存溢出异常)

【0】README0.1&#xff09;本文转自 深入理解 jvm&#xff0c; 旨在学习 OutOfMemoryError 异常&#xff08;内存溢出异常&#xff09; 的触发类型&#xff1b;0&#xff09;准备知识0.1&#xff09;除了程序计数器外&#xff0c;虚拟机内存的其他几个运行时区域&#xff08;方…

java oca_OCA第7部分中的Java难题

java oca在OCA系列的Java Puzzlers的这一部分中&#xff0c;我将展示定义字符串和与之相关的潜在惊喜的多种方法。 创建字符串的两种基本类型是使用new关键字和仅使用字符串文字来创建。 String strWithNew new String( "hey" ); String strWithLiteral "ho&…

Java GC总结

一、gc两大基本算法1、引用计数法 2、根搜索法 二、gc改进收集算法 1、标记-清除算法 2、复制算法 3、标记-整理算法 分代收集算法 三、gc的类型 串行垃圾回收器&#xff08;Serial Garbage Collector&#xff09; 并行垃圾回收器&#xff08;Parallel Garbage Collecto…

让CentOS能用yum自动安装rar和unrar

【0】README 0.1&#xff09;本文转自&#xff1a; http://www.centoscn.com/CentOS/config/2015/0520/5485.html 目的&#xff1a;让CentOS能用yum自动安装rar和unrar 系统环境&#xff1a; CentOS 7.0 具体操作步骤如下&#xff1a; 1.编辑文件 编辑dag.repo文件&#xff0c…