Java语言的组件技术 ;
JavaBean设计目标及其实现手段;
JavaBean中的属性;
JavaBean的事件及自定义事件;
JavaBean持久化
JavaBean的自检
JavaBean的编程实例
一、Java语言的组件技术
1、JavaBean是什么?
(1)Bean是一个特殊的类,这个类必须符合JavaBean规范(是一个非常简单的遵循某种严格协议的Java类)。
(2)JavaBean是用Java语言编写的可重用软件组件。
2、Bean的种类:
可视化软件组件:可以是简单的GUI元素,如按钮或滚动条;也可以是复杂的,如数据库视图
非可视化软件组件:没有GUI表现形式,用于封装业务逻辑、数据库操作等
3、JavaBean与微软的ActiveX的不一样
JavaBean是与平台无关的
ActiveX是基于Windows系统平台的
4、JavaBean组件与EJB的不同:
JavaBean组件存储状态信息
EJB组件存储业务逻辑
5、Bean的应用场合:
在使用Java编程时,并不是所有软件模块都需要转换成Bean。
Bean比较适合于那些具有可视化操作和定制特性的软件组件。
6、JavaBean的开发方法:
采用可视化开发工具---主要有:
Borlands公司的JBuilder
SunSoft的Java Studio
Symantec的Visual Café
IBM的Visual Age for Java等;
当然也可以手写代码。
7、JavaBean的编程要点:
一个Bean不必非要继承特定的基类或接口;
可视化的Bean必须继承的类是Component类,这样它们才能添加到可视化容器中去;
非可视化Bean则不需要继承这个类。
一个Bean本质上就是一个Java类的代码,只是添加了所谓的自检和序列化,因此Bean实际就是一个普通的Java类。
二、JavaBean设计目标及其实现手段
(1)紧凑而方便的创建和使用
因为Bean组件常常用于分布式计算环境中,这使得JavaBean组件常常需要在有限的带宽连接环境下进行传输。
显然,为了适应传送的效率和速度,JavaBean组件必须是越紧凑越好。
(2)完全的可移植性
JavaBean API与独立于平台的Java系统相结合,提供了独立于平台的组件解决方案。因此,组件开发者就可以不必再为带有JavaBean平台特有的类库而担心了。
最终的结果都将是计算机界共享可重复使用的组件,并在任何支持Java的系统中无需修改地执行
(3)继承Java的强大功能
现有的Java结构已经提供了多种易于应用于组件的功能。其中一个比较重要的是Java本身的内置类发现功能,它可以使得对象在运行时彼此动态地交互作用,这样对象就可以从开发系统或其开发历史中独立出来。
JavaBean继承在现有Java功能中还有一个重要的方面,就是持久性,它保存对象并获得对象的内部状态。
通过Java提供的序列化(serialization)机制,持久性可以由JavaBean自动进行处理。
当然,在需要的时候,开发者也可以自己建立定制的持久性方案。
三、一个简单的JavaBean程序代码
import java.awt.*;
import java.io.Serializable;
public class JavaBeanButton extends Canvas implements Serializable
{ //任何实现了Serializable接口的Java类都可以成为一个JavaBean类。
public JavaBeanButton()
{ this.setSize(50,50);
}
public void paint(Graphics g)
{ g.setColor(Color.LIGHT_GRAY);
g.fillOval(0,0,50,50);
}
}
JavaBean程序结构要点
1、可视化的Bean应该从Component或者Canvas类来继承
2、每个Bean应该实现Serializable接口
3、JavaBean中的构造函数
每个JavaBean的类中应该提供一个不带参数的默认构造函数,以便构造工具能够实例化其对象。当然还应该有带参数的构造函数以便能够对它进行初始化。
4、其它则与一般的Java类的编程规则相同
四、JavaBean的存储格式
Jar文件:
JavaBean组件被设计出来后,一般是以扩展名为jar的格式文件存储,在jar中包含与JavaBean有关的信息,并以MANIFEST文件指定其中的哪些类是JavaBean。
Jar文件中的manifest文件的内容如下:
Name: JavaBean.class
Java-Bean: True
利用Jar命令产生*.jar文件。命令格式如下
C> jar cfm JavaBean.jar JavaBeanManifest.txt JavaBean.class
参考JavaBeanStepbyStep中的step1
五、JavaBean中的属性
JavaBean的属性与一般Java程序中所指的属性,或者说与所有面向对象的程序设计语言中对象的属性是一个概念,在程序中的具体体现就是类中的变量。在JavaBean的设计中,按照属性的不同作用又细分为四类:
单值属性
索引属性
关联属性
限制属性
属性一、JavaBean中的单值属性
(1)含义:它表示一个伴随有一对get/set方法的变量。属性名与和该属性相关的get/set方法名对应。
(2)编码规则
属性声明为私有,没有公有的属性
通过访问方法而不是直接存储实例变量
属性值xxx对应有getXxx和setXxx方法
对于布尔型的属性,可以用isXxx方法查值
Bean的普通方法不适合上面的命名规则,但它们是公有的。
JavaBean中的单值属性示例代码
public class myCanvas extends Canvas implements Serializable
{
String ourString= "Hello"; //属性名为ourString,类型为字符串
boolean editable; public myCanvas()
{ setBackground(Color.red);
setForeground(Color.blue); }
public void setOurString(String newString)
{ /* “set”属性*/
ourString=newString; } public String getOurString()
{ /* "get"属性 */
return ourString; }
public boolean isEditable()
{ /* "布尔"属性 */
return editable; }
}
属性二、JavaBean中的索引属性
含义:
它表示一个数组值。使用与该属性对应的set/get方法可取得数组中的成员数据值(需要有一个整数索引参数)或者一次设置或取得整个数组的值。
索引属性的设计模式如下:
(1)访问整个索引属性数组的方法
public []get ();
public void set ([]value);
(2)访问整个索引属性中的单个值的方法
public get (int index);
public void set (int index,int value);
JavaBean中的索引属性示例代码
public class myCanvas extends Canvas implements Serializable
{ int[] dataSet={1,2,3,4,5,6}; //dataSet是一个索引属性 public myCanvas()
{ setBackground(Color.red);
setForeground(Color.blue); }
public void setDataSet(int[] newdataSet)//设置整个数组
{ dataSet= newdataSet; } /* 设置数组中的单个元素值 */
public int[] getDataSet() /* 取得整个数组值 */
{ return dataSet; }
public void setDataSet(int index, int x)
{ dataSet[index]=x; } public int getDataSet(int index)
{ /* 取得数组中的指定元素值 */
return dataSet[index]; }
}
属性三、JavaBean中的关联属性
含义:
它是指当该种属性的值发生变化时,要通知其它的对象。
每次的属性值改变时,这种属性就点火一个PropertyChange事件。
事件中封装了属性名、属性的原值、属性变化后的新值。
至于接收事件的Bean应做什么动作由其自己定义。
包含关联属性的Bean必须具有以下的功能:
允许事件监听器注册和注销与其有关的属性修改事件;
当修改一个关联属性时,可以在相关的监听器上触发属性修改事件。
在java.beans包中利用PropertyChangeSupport类创建出该类的对象,从而可以用于管理注册的监听器列表和属性修改事件通知的发送。
关联属性的编程要点
1、由于当关联属性被改变时,将使用PropertyChangeSupport类中的firePropertyChange方法来点火属性改变事件。
2、应该存储关联属性的原始属性值,因为属性值和新的属性值都要传给firePropertyChange()方法,而且它们都是Object类型。因此如果为基本的数据,则应该转换为对应的类类型。
3、属性修改事件是在属性被修改后触发。
changes.firePropertyChange("ourString",oldString,newString);
4、Bean要预留出一些接口给开发工具,开发工具使用这些接口,把其它的JavaBean对象与该Bean相挂接。
public void addPropertyChangeListener(PropertyChangeListener listener)
{changes.addPropertyChangeListener(listener);}
public void removePropertyChangeListener(PropertyChangeListener listener)
{changes.removePropertyChangeListener(listener);}
属性四、JavaBean中的限制属性
含义:
它指当这个属性的值要发生变化时,与这个属性已建立了某种连接的其它外部Java对象可否决该属性值的改变;
当然Bean 本身也可以否决该Bean属性值的改变。
如何限制属性: 限制属性的监听者通过抛出PropertyVetoException来阻止该属性值的改变。
监听者:限制属性一般有两种监听者
属性变化监听者
否决属性改变的监听者
否决属性改变的监听者在自己的对象代码中有相应的控制语句,在监听到有限制属性要发生变化时,在控制语句中判断是否应否决这个属性值的改变
限制属性的编程要点
1、分别声明PropertyChangeSupport和VetoableChangeSupport类的对象(限制属性值可否改变 )
2、当属性被改变时,然后点火属性改变否决事件。
vetos.fireVetoableChange(…);
3、若有其它对象否决属性的改变,则程序抛出异常,不再继续执行下面的语句,方法结束。若无其它对象否决属性的改变,则把该属性赋予新值,并点火属性改变事件。
4、与属性改变事件相同,也要为限制属性预留接口,使其它对象可注册入限制属性的否决改变监听者队列中,或把该对象从中注销。
5、限制属性实际上是一种特殊的关联属性,只是它的值的变化可以被监听者否决掉。
public void addVetoableChangeListener(VetoableChangeListener listener)
{
vetos.addVetoableChangeListener(listener); } public void removeVetoableChangeListener(VetoableChangeListener listener)
{
vetos.removeVetoableChangeListener(listener); }
六、JavaBean的事件编程
1、通过事件处理机制
可让一些组件作为事件源,发出可被描述环境或其它组件接收的事件。
这样,不同的组件就可在构造工具内组合在一起,组件与组件、组件与外界之间通过事件的传递进行通信,构成一个应用。
2、JavaBean事件模型的总体结构(略)
3、事件监听者的注册与注销
为了各种可能的事件监听者把自己注册入合适的事件源中,建立源与事件监听者间的事件流,事件源必须为事件监听者提供注册和注销的方法。
public void add< ListenerType> (< ListenerType> listener);
public void remove< ListenerType> (< ListenerType> listener);
4、事件编程的步骤
声明指定的事件接口对象
允许触发该类型的事件
实现维护该事件的监听器列表的方法(应该包含有添加和删除)
向所有注册该类型的事件组件分发该事件
七、JavaBean 的自检
(1)含义:
使外部组件能够寻找到关于JavaBean的结构和功能的内部信息。
(2)方法:
利用设计模式来隐含地提供自检信息。
由于Bean中的属性、方法、事件等的命名有一定的规则,外部系统可以利用这些规则来获得Bean的结构和功能的内部信息。
属性设计模式
事件设计模式
方法设计模式
利用BeanInfo提供显示信息
1、利用属性设计模式提供自检信息
属性设计模式:
用于标识Bean 中的公有的可访问的属性,即依赖getXXX()、setXXX()、isXXX()等访问者方法来决定可访问的属性。
2、利用事件设计模式提供自检信息
事件设计模式:
Bean将事件通知发送给需要接收这些通知并已经在这个Bean上注册了的事件监听器。
因为事件监听器必须在Bean上进行注册,所以需要Bean提供适当的方法来实现注册过程。
因为在JavaBean的自检机制中,可以从注册方法的名字以及方法的参数类型检测到事件源会产生什么事件。
事件设计模式编程要点
事件注册方法常常是成对出现(添加和删除)。
JavaBean的自检器正是使用这些方法访问Bean可以发送的事件。
事件注册必须遵循如下的事件设计模式,以便自动自检服务可以正确地进行
public void add ( e);
public void remove( e);
3、利用方法设计模式提供自检信息
由于这些public方法是完全由Bean的设计者定义的,它们在各个Bean中没有固定的使用特征,因此对这些方法没有特定的设计模式要遵循。
要求:
Bean可以在一个单独的相关类中显示地表现它的特征,这个类应该实现BeanInfo接口或是继承SimpleBeanInfo类来显示地表现可以被构造器工具获取的Bean的设计环境信息。
编程的方法:
将Bean的相关信息类的名称后加“BeanInfo”
继承SimpleBeanInfo类(它实现了BeanInfo接口)
在Bean的相关信息类中实现所需要的BeanInfo接口中的方法以显式地提供Bean的信息。
import java.beans.*;
public class JavaBeanButtonBeanInfo extends SimpleBeanInfo
{ public Image getIcon(int iconKind)
{//以下代码为JavaBean提供16*16和32*32的图标
}
public BeanDescriptor getBeanDescriptor()
{//以下代码为JavaeBean提供在应用程序的构造工具中的显示名称字串
}
public PropertyDescriptor[] getPropertyDescriptors()
{ //以下代码显式地声明属性
}
public int getDefaultPropertyIndex()
{ return 5;//将某个属性作为缺省的属性
}
public EventSetDescriptor[] getEventSetDescriptors()
{ //为Bean显式地注册事件接口
}
}
八、JavaBean持久化
含义: 通过持久化,可以将Bean的内部状态(某些字段的信息)保存下来并备以后使用。
实现机制:
Bean的持久化是基于Java的对象序列化机制的。因此在定义Bean时要使它实现Serializable接口。
存储位置:可以存储在文件中。 要点:
任何实现了Serializable接口的Java类都可以成为一个JavaBean类。
JavaBean持久化的形式
(一)默认的序列化:
实现了Serializable序列化接口的Bean中字段的信息将被自动保存。
若不想保存某些字段的信息则可在这些字段前冠以transient或static关键字
transient和static变量的信息是不可被保存的。因为transient代表Bean在某次特定会话期间的信息,是临时变量,没有必要永久保存。
默认的序列化编程要点
(1)一个Bean中所有public属性都应当是被保存的,也可有选择地保存内部状态。
(2)Bean开发者在修改软件时,可以添加字段、移走对其它类的引用,改变一个字段的private/protected/public状态,这些都不影响类的存储结构关系。
(3)实现了Serializable序列化接口的类必须有一个无参数的构造函数,重建对象时需要调用它。
(4)当从类中删除一个字段,改变一个变量在类体系中的位置,把某个字段改成transient/static,或原来是transient/static,现改为别的特性时,都将引起存储关系的变化。
(5)如果Bean的基类已经实现了序列化接口,则该Bean可以不必再实现它。
(二)对默认的序列化进行定制,在Bean类中重写readObject()与writeObject()方法定制序列化的数据。
如果在可序列化的Bean中包含有上面两个方法,则可以实现定制序列化
应用场合:
希望对序列化的过程执行更多的控制(选择性地进行序列化)。
序列化不能由默认的序列化完成的数据如static数据
或者需要向序列化数据中添加不是对象数据成员的数据时(附加的数据)。
但要求它们为private方法。
定制序列化的示例代码
private void writeObject(ObjectOutputStream out) throws IOException
{ out.defaultWriteObject();
//先进行默认的序列化写操作
out.writeInt(JavaBeanButtonVersion );
//再写入static 的JavaBeanButtonVersion数据
}
private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException
{ in.defaultReadObject();
//先进行默认的序列化读操作
JavaBeanButtonVersion =in.readInt();
//再读出static 的JavaBeanButtonVersion数据
}