提示,重点:JavaBeans的Property和 Events;PropertyEditor极其注册查找机制。


从目前来看,JavaBeans 更像是源自GUI的需求。

使用NetBeans新建一个Java Application,然后新建一个jFrame form,右边会有组件面板,如下:

这些组件,本质上都是bean!所以可被复用、可被引用、可被通知!

将任意一个组件拖进去安置,例如Button(按钮)。如下:

在右下角会显示该组件的属性,如下:

如果是英文版的NetBeans,你就会发现这里的属性就是Properties。你在这里进行的所有设置,如设置图标、字体、边框、背景等等操作,本质上都是调用相应的SETTER!(在SETTER之前会先调用PropertyEditor)

官方文档有这么一句:

A bean is a Java class with method names that follow the JavaBeans guidelines. A bean builder tool uses introspection to examine the bean class. Based on this inspection, the bean builder tool can figure out the bean's properties, methods, and events. -- 原文

类似Netbeans这样的builder tool,会识别并展示所有的property name and type,以及其他,以方便设计者在设计时进行操作。

JavaBeans’ property 中有两个特殊的:bound property、constrained property,如下:

bound property,当其值发生改变时,会通知监听器!两个含义:

1,该bean类包含两个方法:addPropertyChangeListener() and removePropertyChangeListener()

2,当值发生改变时,该bean会发送PropertyChangeEvent至注册过的监听器。

PropertyChangeEvent and PropertyChangeListener 都在 java.beans package中。

该包中还有一个类,PropertyChangeSupport,负责多数的bound properties工作。

代码示例如下:

import java.beans.*;

public class FaceBean {
private int mMouthWidth = 90;
private PropertyChangeSupport mPcs = new PropertyChangeSupport(this); // 这里 public int getMouthWidth() {
return mMouthWidth;
} public void setMouthWidth(int mw) {
int oldMouthWidth = mMouthWidth; //
mMouthWidth = mw;
mPcs.firePropertyChange("mouthWidth", oldMouthWidth, mw); // 这里
} // 这里
public void addPropertyChangeListener(PropertyChangeListener listener) {
mPcs.addPropertyChangeListener(listener);
} // 这里
public void removePropertyChangeListener(PropertyChangeListener listener) {
mPcs.removePropertyChangeListener(listener);
}
}

constrained property,一种特殊的 bound property。bean会持续跟踪 a set of veto listeners。当constrained property 将要发生改变时,会先咨询监听器。任何一个veto listener都有机会否决这次改变,就是说,维持原值不变。

veto listeners独立于 property change listener。所幸, java.beans 包包含了一个 VetoableChangeSupport 类,可以极大的简化 constrained properties。

import java.beans.*;

public class FaceBean {
private int mMouthWidth = 90;
private PropertyChangeSupport mPcs = new PropertyChangeSupport(this);
private VetoableChangeSupport mVcs = new VetoableChangeSupport(this); // 这里 public int getMouthWidth() {
return mMouthWidth;
} public void setMouthWidth(int mw) throws PropertyVetoException {
int oldMouthWidth = mMouthWidth;
mVcs.fireVetoableChange("mouthWidth", oldMouthWidth, mw); // 这里
mMouthWidth = mw;
mPcs.firePropertyChange("mouthWidth", oldMouthWidth, mw);
} public void addPropertyChangeListener(PropertyChangeListener listener) {
mPcs.addPropertyChangeListener(listener);
} public void removePropertyChangeListener(PropertyChangeListener listener) {
mPcs.removePropertyChangeListener(listener);
}
    // 这里
public void addVetoableChangeListener(VetoableChangeListener listener) {
mVcs.addVetoableChangeListener(listener);
} // 这里
public void removeVetoableChangeListener(VetoableChangeListener listener) {
mVcs.removeVetoableChangeListener(listener);
}
}

JavaBeans’ method: A bean's methods are the things it can do. Any public method that is not part of a property definition is a bean method.

JavaBeans’ events: A bean class can fire off any type of event, including custom events.

和property一样,event也有自己的惯例:

public void add<Event>Listener(<Event>Listener a)

public void remove<Event>Listener(<Event>Listener a)

注意,listener必须是 java.util.EventListener 的子类。

类似NetBeans的builder tool可以识别 bean events。

使用BeanInfo

Beans,特别是图形组件,可能拥有大量的properties,难以快速的找到正确的properties进行编辑 -- 特别是对于新手来说。

BeanInfo可以改变bean在builder tool中的展示形式。Builder tool可以查询BeanInfo以找出哪些properties优先展示,哪些应该隐藏。

BeanInfo和bean的名字一样,但以 BeanInfo 结尾。例如,FaceBean与FaceBeanBeanInfo。

虽然可以手动创建BeanInfo,但是使用工具(如NetBeans)更简洁。

NetBeans中创建Bean的BeanInfo很简单,右键 - BeanInfo Editor… 即可。第一次会提示创建,同意即可。

默认进入源码编辑界面,记得切入设计界面。如下:

可以针对property进行选择,主要就是是否优先展示、是否隐藏、是否bound property、是否constrained property。

builder tool在发现一个bean类之后,会自动查找同路径下的BeanInfo,以决定如何展示bean。


JavaBeans入门很简单,但这货其实是很有深度的。现在来看点高级货,包括 如何持久化保存一个bean、如何为定制的类型提供定制的editor。

Bean Persistence (持久化)

想了下,这个也是源自GUI吧,总不能每次打开的界面都是最原始的界面。

The mechanism that makes persistence possible is called serialization. Object serialization means converting an object into a data stream and writing it to storage. Any applet, application, or tool that uses that bean can then "reconstitute" it by deserialization. The object is then restored to its original state.

囧了,居然是序列化和反序列化。

All beans must persist. To persist, your beans must support serialization by implementing either the java.io.Serializable (in the API reference documentation) interface, or the java.io.Externalizable (in the API reference documentation) interface. These interfaces offer you the choices of automatic serialization and customized serialization.

原来有两个接口,涨姿势了。

实现 Serializable的bean,可以自动序列化/反序列化,会自动忽略transient和static的字段。

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream. This includes primitive types, arrays,and strings. The API does not serialize or deserialize fields that are marked transient or static.

你可以控制你的bean的序列化level!三种途径:

    • 自动序列化,实现Serializable接口即可。序列化整个对象,除了transient 和 static 字段。

    • 定制序列化。将不想序列化的自动使用transient 或 static 修饰。— 囧。
    • 定制文件格式,实现 Externalizable和其两个方法。Bean会被以那种文件格式写入。

默认序列化:Serializable接口,就是一个标记,告诉JVM希望进行默认序列化。有几个关键点需要知道:

类必须有一个针对父类无参构造的访问。

如果父类实现了Serializable接口,子类可以继承。

会忽略transient 和 static。 -- 各种重复啊

选择性序列化:writeObject 和 readObject

如果你的serializable class含有下面两个方法中的任意一个,默认的序列化就不会发生:

private void writeObject(java.io.ObjectOutputStream out) throws IOException;

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;

通过这两个方法,你可以控制如何序列化/反序列化。

Externalizable接口

完全控制bean的序列化/反序列化(例如,以一种特定文件格式进行读写)。

需要实现两个方法:writeExternal和readExternal。

实现类必须有一个无参构造。

Long Term Persistence 长期持久化

Long-term persistence is a model that enables beans to be saved in XML format.

居然只支持XML格式。

Encoder 和 Decoder

XMLEncoder类用于输出Serializable对象。例如:

XMLEncoder encoder = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream("Beanarchive.xml"))); encoder.writeObject(object);
encoder.close();

XMLDecoder类读取XMLEncoder创建的XML:

XMLDecoder decoder = new XMLDecoder(
new BufferedInputStream(
new FileInputStream("Beanarchive.xml"))); Object object = decoder.readObject();
decoder.close();

下面是SimpleBean的XML形式:

<?xml version="1.0" encoding="UTF-8" ?>
<java>
<object class="javax.swing.JFrame">
<void method="add">
<object class="java.awt.BorderLayout" field="CENTER"/>
<object class="SimpleBean"/>
</void>
<void property="defaultCloseOperation">
<object class="javax.swing.WindowConstants" field="DISPOSE_ON_CLOSE"/>
</void>
<void method="pack"/>
<void property="visible">
<boolean>true</boolean>
</void>
</object>
</java>

Bean Customization 定制

修改一个bean的appearance和behaviour,两种方式:

  • 通过一个property editor。

  • 通过customizer。 同property editor的区别是,customizer关联到bean,property editor关联到property。

PropertyEditor

这里的属性设值,都是调用了相应的PropertyEditor!-- 因为你输入的都是字符串啦。

例如,点击 toolTipText 后面的【…】,就会打开一个StringEditor window:

PropertyEditorSupport提供PropertyEditor接口的空实现,继承它,按需覆盖方法即可完成自己的PropertyEditor。

Property Editors 是如何关联到 Properties 的? (重点)

  • 通过一个BeanInfo对象 显式的关联。

  • 通过java.beans.PropertyEditorManager.registerEditor方法 显式的注册。
  • 名字查找。如果一个类没有显式的关联PropertyEditor,那 PropertyEditorManager 会按以下顺序搜索其editor:

同包路径下以类的名字开始,以’Editor’结束。

在classpath中搜索(以类的名字开始,以’Editor’结束)!

Customizers (可以忽略)

在bean层次上configure或edit一个bean。

所有的customizer 必须:

  • 继承 java.awt.Component 或其子类。

  • 实现 java.beans.Customizer 接口。就是实现注册 PropertyChangeListener对象的方法。
  • 默认构造。
  • 通过BeanInfo.getBeanDescriptor将customizer关联到目标类。

参考文档:

The Java™ Tutorials,Trail: JavaBeans(TM)

JavaBeans 官方文档学习的更多相关文章

  1. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion(一)

    题外话:本篇是对之前那篇的重排版.并拆分成两篇,免得没了看的兴趣. 前言 在Spring Framework官方文档中,这三者是放到一起讲的,但没有解释为什么放到一起.大概是默认了读者都是有相关经验的 ...

  2. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion

    本篇太乱,请移步: Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 写了删删了写,反复几次,对自己的描述很不 ...

  3. Spring 4 官方文档学习(十二)View技术

    关键词:view technology.template.template engine.markup.内容较多,按需查用即可. 介绍 Thymeleaf Groovy Markup Template ...

  4. Spring 4 官方文档学习(十一)Web MVC 框架之配置Spring MVC

    内容列表: 启用MVC Java config 或 MVC XML namespace 修改已提供的配置 类型转换和格式化 校验 拦截器 内容协商 View Controllers View Reso ...

  5. Spring Data Commons 官方文档学习

    Spring Data Commons 官方文档学习   -by LarryZeal Version 1.12.6.Release, 2017-07-27 为知笔记版本在这里,带格式. Table o ...

  6. Spring 4 官方文档学习(十一)Web MVC 框架之resolving views 解析视图

    接前面的Spring 4 官方文档学习(十一)Web MVC 框架,那篇太长,故另起一篇. 针对web应用的所有的MVC框架,都会提供一种呈现views的方式.Spring提供了view resolv ...

  7. Spring 4 官方文档学习(十一)Web MVC 框架

    介绍Spring Web MVC 框架 Spring Web MVC的特性 其他MVC实现的可插拔性 DispatcherServlet 在WebApplicationContext中的特殊的bean ...

  8. Spring Boot 官方文档学习(一)入门及使用

    个人说明:本文内容都是从为知笔记上复制过来的,样式难免走样,以后再修改吧.另外,本文可以看作官方文档的选择性的翻译(大部分),以及个人使用经验及问题. 其他说明:如果对Spring Boot没有概念, ...

  9. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion(二)

    接前一篇 Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 本篇主要内容:Spring Type Conver ...

随机推荐

  1. ubuntu系统——增加磁盘空间

    1.df查看磁盘使用情况 2.将windows下的磁盘空间分出与部分给ubuntu 3.格式化磁盘    在终端输入:mkfs -t ext3 /dev/sdb1    用ext3格式对/dev/sd ...

  2. C3P0连接参数解释

    <c3p0-config> <default-config> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数.Default: 3 --> < ...

  3. cxf 生成客户端代码调用服务

    cxf是另一种发布webservice的方式,与jdk提供的相比 jdk提供的是wsimport cxf 提供的是 wsdl2java- d 地址 根据http://www.cnblogs.com/f ...

  4. vue使用axios,进行网络请求

    1.首先自己创建一个组件: https://www.cnblogs.com/fps2tao/p/9559291.html 2.安装:axios(可以npm安装,也可以下载js引入文件) npm ins ...

  5. WCF实现RESTFul Web Service

    共同学习了前面一些概念,终于开始正题了哈.RESTful的Web Service调用直观,返回的内容容易解析.这里先会描述一个简单的场景--Web Service提供一个方法来搜索个人信息,传入人名, ...

  6. 逆向project第005篇:跨越CM4验证机制的鸿沟(下)

    一.前言 本文是逆向分析CM4系列的最后一篇,我会将该游戏的序列号验证机制分析完成,进而编写出注冊码生成器. 二.分析第二个验证循环 延续上一篇文章的内容,来到例如以下代码处: 图1 上述代码并没有特 ...

  7. atitit. 文件上传带进度条 atiUP 设计 java c# php

    atitit. 文件上传带进度条 atiUP 设计 java c# php 1. 设计要求 1 2. 原理and 架构 1 3. ui 2 4. spring mvc 2 5. springMVC.x ...

  8. CHero

    #ifndef __HERO_H__ #define __HERO_H__ #include "GameFrameHead.h" #include "GameParam. ...

  9. zookeeper是如何选取主leader的?

    以一个简单的例子来说明整个选举的过程.假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序 ...

  10. Activiti工作流简单入门 (zhuan)

    https://my.oschina.NET/Barudisshu/blog/309721 *********************************************** 摘要: 自j ...