- 浏览: 1336925 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
kay11:
...
JAVA生成简单的随机字符串(a-zA-Z0-9) -
zhangliguoaccp:
您好关于登录页面的验验证码这块怎么解决的?还有登录成功后,跳转 ...
JAVA,模拟HTTP登录 -
107x:
不错,谢谢!
<c:foreach 循环 map -
wenjin:
不知楼主是不还在想请叫一下我自己开的Tomcat下载一个文件C ...
Android 下载文件及写入SD卡 -
zyywgf:
JSTL c标签,fn标签,fmt标签
JavaBeans的属性
JavaBeans的属性与一般Java程序中所指的属性,或者说与所有面向对象的程序设计语言中对象的属性是一个概念,在程序中的具体体现就是类中的变量。在JavaBeans设计中,按照属性的不同作用又细分为四类:Simple,Index,Bound与Constrained属性。
1.Simple属性
一个简单属性表示一个伴随有一对get/set方法(C语言的过程或函数在Java程序中称为"方法")的变量。属性名与和该属性相关的get/set方法名对应。例如:如果有setX和getX方法,则暗指有一个名为"X"的属性。如果有一个方法名为isX,则通常暗指"X"是一个布尔属性(即X的值为true或false)。例如在下面这个程序中:
publicclassalden1extendsCanvas{
stringourString="Hello";//属性名为ourString,类型为字符串
publicalden1(){ //alden1()是alden1的构造函数,
与C++中构造函数的意义相同
setBackground(Color.red);
setForeground(Color.blue);
}
/*"set"属性*/
publicvoidsetString(StringnewString){
ourString=newString;
}
/*"get"属性*/
publicStringgetString(){
returnourString;
}
}
2.Indexed属性
一个Indexed属性表示一个数组值。使用与该属性对应的set/get方法可取得数组中的数值。该属性也可一次设置或取得整个数组的值。例:
publicclassalden2extendsCanvas{
int[]dataSet={1,2,3,4,5,6};//dataSet是一个indexed属性
publicalden2(){
setBackground(Color.red);
setForeground(Color.blue);
}
/*设置整个数组 */
publicvoidsetDataSet(int[]x){
dataSet=x;
}
/*设置数组中的单个元素值*/
publicvoidsetDataSet(intindex,intx){
dataSet[index]=x;
}
/*取得整个数组值*/
publicint[]getDataSet(){
returndataSet;
}
/*取得数组中的指定元素值*/
publicintgetDataSet(intx){
returndataSet[x];
}
}
3.Bound属性
一个Bound属性是指当该种属性的值发生变化时,要通知其它的对象。每次属性值改变时,这种属性就点火一个PropertyChange事件(在Java程序中,事件也是一个对象)。事件中封装了属性名、属性的原值、属性变化后的新值。这种事件是传递到其它的Beans,至于接收事件的Beans应做什么动作由其自己定义。当PushButton的background属性与Dialog的background属性bind时,若PushButton的background属性发生变化时,Dialog的background属性也发生同样的变化。例:
publicclassalden3extendsCanvas{
StringourString="Hello";
//ourString是一个bound属性
privatePropertyChangeSupportchanges=newPropertyChangeSupport(this);
/**注:Java是纯面向对象的语言,
如果要使用某种方法则必须指明是要使用哪个对象的方法,
在下面的程序中要进行点火事件的操作,
这种操作所使用的方法是在PropertyChangeSupport类中的。
所以上面声明并实例化了一个changes对象,
在下面将使用changes的firePropertyChange方法来点火ourString的属性改变事件。*/
publicvoidsetString(stringnewString){
StringoldString=ourString;
ourString=newString;
/*ourString的属性值已发生变化,于是接着点火属性改变事件*/
changes.firePropertyChange("ourString",oldString,newString);
}
publicStringgetString(){
returnourString;
}
/**以下代码是为开发工具所使用的。
我们不能预知alden3将与哪些其它的Beans组合成为一个应用,
无法预知若alden3的ourString属性发生变化时有哪些其它的组件与此变化有关,
因而alden3这个Beans要预留出一些接口给开发工具,
开发工具使用这些接口,
把其它的JavaBeans对象与alden3挂接。*/
publicvoidaddPropertyChangeListener(PropertyChangeLisenerl){
changes.addPropertyChangeListener(l);
}
publicvoidremovePropertyChangeListener(PropertyChangeListenerl){
changes.removePropertyChangeListener(l);
}
通过上面的代码,
开发工具调用changes的addPropertyChangeListener方法
把其它JavaBeans注册入ourString属性的监听者队列l中,
l是一个Vector数组,可存储任何Java对象。
开发工具也可使用changes的removePropertyChangeListener方法,
从l中注销指定的对象,
使alden3的ourString属性的改变不再与这个对象有关。
当然,当程序员手写代码编制程序时,
也可直接调用这两个方法,
把其它Java对象与alden3挂接。
4.Constrained属性
一个JavaBeans的constrained属性,是指当这个属性的值要发生变化时,与这个属性已建立了某种连接的其它Java对象可否决属性值的改变。constrained属性的监听者通过抛出PropertyVetoException来阻止该属性值的改变。例:下面程序中的constrained属性是PriceInCents。
publicclassJellyBeansextendsCanvas{
privatePropertyChangeSupportchanges=newPropertyChangeSupport(this);
privateVetoableChangeSupportVetos=newVetoableChangeSupport(this);
/*与前述changes相同,
可使用VetoableChangeSupport对象的实例Vetos中的方法,
在特定条件下来阻止PriceInCents值的改变。*/
......
publicvoidsetPriceInCents(intnewPriceInCents)throwsPropertyVetoException{
/*方法名中throwsPropertyVetoException的作用是当有
其它Java对象否决PriceInCents的改变时,
要抛出例外。*/
/*先保存原来的属性值*/
intoldPriceInCents=ourPriceInCents;
/**点火属性改变否决事件*/
vetos.fireVetoableChange("priceInCents",newInteger(OldPriceInCents),
newInteger(newPriceInCents));
/**若有其它对象否决priceInCents的改变,
则程序抛出例外,不再继续执行下面的两条语句,
方法结束。若无其它对象否决priceInCents的改变,
则在下面的代码中把ourPriceIncents赋予新值,
并点火属性改变事件*/
ourPriceInCents=newPriceInCents;
changes.firePropertyChange("priceInCents",
newInteger(oldPriceInCents),
newInteger(newPriceInCents));
}
/**与前述changes相同,
也要为PriceInCents属性预留接口,
使其它对象可注册入PriceInCents否决改变监听者队列中,
或把该对象从中注销
publicvoidaddVetoableChangeListener(VetoableChangeListenerl)
{vetos.addVetoableChangeListener(l);
}
publicvoidremoveVetoableChangeListener(VetoableChangeListenerl){
vetos.removeVetoableChangeListener(l);
}
......
}
从上面的例子中可看到,一个constrained属性有两种监听者:属性变化监听者和否决属性改变的监听者。否决属性改变的监听者在自己的对象代码中有相应的控制语句,在监听到有constrained属性要发生变化时,在控制语句中判断是否应否决这个属性值的改变。
总之,某个Beans的constrained属性值可否改变取决于其它的Beans或者是Java对象是否允许这种改变。允许与否的条件由其它的Beans或Java对象在自己的类中进行定义。
JavaBeans的事件
事件处理是JavaBeans体系结构的核心之一。通过事件处理机制,可让一些组件作为事件源,发出可被描述环境或其它组件接收的事件。这样,不同的组件就可在构造工具内组合在一起,组件之间通过事件的传递进行通信,构成一个应用。从概念上讲,事件是一种在"源对象"和"监听者对象"之间,某种状态发生变化的传递机制。事件有许多不同的用途,例如在Windows系统中常要处理的鼠标事件、窗口边界改变事件、键盘事件等。在Java和JavaBeans中则是定义了一个一般的、可扩充的事件机制,这种机制能够:
对事件类型和传递的模型的定义和扩充提供一个公共框架,并适合于广泛的应用。
与Java语言和环境有较高的集成度。
事件能被描述环境捕获和点火。
能使其它构造工具采取某种技术在设计时直接控制事件,以及事件源和事件监听者之间的联系。
事件机制本身不依赖于复杂的开发工具。特别地,还应当:
能够发现指定的对象类可以生成的事件。
能够发现指定的对象类可以观察(监听)到的事件。
提供一个常规的注册机制,允许动态操纵事件源与事件监听者之间的关系。
不需要其它的虚拟机和语言即可实现。
事件源与监听者之间可进行高效的事件传递。
能完成JavaBeans事件模型与相关的其它组件体系结构事件模型的中立映射。
JavaBeans事件模型的主要构成有:事件从事件源到监听者的传递是通过对目标监听者对象的Java方法调用进行的。对每个明确的事件的发生,都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者(EventListener)接口中,这个接口要继承java.util.EventListener。实现了事件监听者接口中一些或全部方法的类就是事件监听者。伴随着事件的发生,相应的状态通常都封装在事件状态对象中,该对象必须继承自java.util.EventObject。事件状态对象作为单参传递给应响应该事件的监听者方法中。发出某种特定事件的事件源的标识是:遵从规定的设计格式为事件监听者定义注册方法,并接受对指定事件监听者接口实例的引用。有时,事件监听者不能直接实现事件监听者接口,或者还有其它的额外动作时,就要在一个源与其它一个或多个监听者之间插入一个事件适配器类的实例,来建立它们之间的联系。
事件状态对象(EventStateObject)
与事件发生有关的状态信息一般都封装在一个事件状态对象中,这种对象是java.util.EventObject的子类。按设计习惯,这种事件状态对象类的名应以Event结尾。例如:
publicclassMouseMovedExampleEventextendsjava.util.EventObject
{protectedintx,y;
/* 创建一个鼠标移动事件MouseMovedExampleEvent*/
MouseMovedExampleEvent(java.awt.Componentsource,Pointlocation){
super(source);
x=location.x;
y=location.y;
}
/*获取鼠标位置*/
publicPointgetLocation(){
returnnewPoint(x,y);
}}
事件监听者接口(EventListenerInterface)与事件监听者
由于Java事件模型是基于方法调用,因而需要一个定义并组织事件操纵方法的方式。JavaBeans中,事件操纵方法都被定义在继承了java.util.EventListener类的EventListener接口中,按规定,EventListener接口的命名要以Listener结尾。任何一个类如果想操纵在EventListener接口中定义的方法都必须以实现这个接口方式进行。这个类也就是事件监听者。例如:
/*先定义了一个鼠标移动事件对象*/
publicclassMouseMovedExampleEvent
extendsjava.util.EventObject{
//在此类中包含了与鼠标移动事件有关的状态信息
...
}
/*定义了鼠标移动事件的监听者接口*/
interfaceMouseMovedExampleListener
extendsjava.util.EventListener{
/*在这个接口中定义了鼠标移动事件监听者所应支持的方法*/
voidmouseMoved(MouseMovedExampleEventmme);
}
在接口中只定义方法名,
方法的参数和返回值类型。
如:上面接口中的mouseMoved方法的
具体实现是在下面的ArbitraryObject类中定义的。
classArbitraryObjectimplementsMouseMovedExampleListener{
publicvoidmouseMoved(MouseMovedExampleEventmme)
{...}
}
ArbitraryObject就是MouseMovedExampleEvent事件的监听者。
事件监听者的注册与注销
为了各种可能的事件监听者把自己注册入合适的事件源中,建立源与事件监听者间的事件流,事件源必须为事件监听者提供注册和注销的方法。在前面的bound属性介绍中已看到了这种使用过程,在实际中,事件监听者的注册和注销要使用标准的设计格式:
publicvoidadd<ListenerType>(<ListenerType>listener);
publicvoidremove<ListenerType>(<ListenerType>listener);
例如:
首先定义了一个事件监听者接口:
publicinterface
ModelChangedListenerextendsjava.util.EventListener{
voidmodelChanged(EventObjecte);
}
接着定义事件源类:
publicabstractclassModel{
privateVectorlisteners=newVector();//定义了一个储存事件监听者的数组
/*上面设计格式中的<ListenerType>在此处即是下面的ModelChangedListener*/
publicsynchronizedvoidaddModelChangedListener(ModelChangedListenermcl)
{listeners.addElement(mcl);}//把监听者注册入listeners数组中
publicsynchronizedvoidremoveModelChangedListener(ModelChangedListenermcl)
{listeners.removeElement(mcl);//把监听者从listeners中注销
}
/*以上两个方法的前面均冠以synchronized,
是因为运行在多线程环境时,
可能同时有几个对象同时要进行注册和注销操作,
使用synchronized来确保它们之间的同步。
开发工具或程序员使用这两个方法建立源与监听者之间的事件流*/
protectedvoidnotifyModelChanged(){
/**事件源使用本方法通知监听者发生了modelChanged事件*/
Vectorl;
EventObjecte=newEventObject(this);
/*首先要把监听者拷贝到l数组中,
冻结EventListeners的状态以传递事件。
这样来确保在事件传递到所有监听者之前,
已接收了事件的目标监听者的对应方法暂不生效。*/
synchronized(this){
l=(Vector)listeners.clone();
}
for(inti=0;i<l.size();i++){
/*依次通知注册在监听者队列中的每个监听者发生了modelChanged事件,
并把事件状态对象e作为参数传递给监听者队列中的每个监听者*/
((ModelChangedListener)l.elementAt(i)).modelChanged(e);
}
}
}
在程序中可见事件源Model类显式地调用了接口中的modelChanged方法,实际是把事件状态对象e作为参数,传递给了监听者类中的modelChanged方法。
适配类
适配类是Java事件模型中极其重要的一部分。在一些应用场合,事件从源到监听者之间的传递要通过适配类来"转发"。例如:当事件源发出一个事件,而有几个事件监听者对象都可接收该事件,但只有指定对象做出反应时,就要在事件源与事件监听者之间插入一个事件适配器类,由适配器类来指定事件应该是由哪些监听者来响应。
适配类成为了事件监听者,事件源实际是把适配类作为监听者注册入监听者队列中,而真正的事件响应者并未在监听者队列中,事件响应者应做的动作由适配类决定。目前绝大多数的开发工具在生成代码时,事件处理都是通过适配类来进行的。
JavaBeans用户化
JavaBeans开发者可以给一个Beans添加用户化器(Customizer)、属性编辑器(PropertyEditor)和BeansInfo接口来描述一个Beans的内容,Beans的使用者可在构造环境中通过与Beans附带在一起的这些信息来用户化Beans的外观和应做的动作。一个Beans不必都有BeansCustomizer、PrpertyEditor和BeansInfo,根据实际情况,这些是可选的,当有些Beans较复杂时,就要提供这些信息,以Wizard的方式使Beans的使用者能够用户化一个Beans。有些简单的Beans可能这些信息都没有,则构造工具可使用自带的透视装置,透视出Beans的内容,并把信息显示到标准的属性表或事件表中供使用者用户化Beans,前几节提到的Beans的属性、方法和事件名要以一定的格式命名,主要的作用就是供开发工具对Beans进行透视。当然也是给程序员在手写程序中使用Beans提供方便,使他能观其名、知其意。
用户化器接口(CustomizerInterface)
当一个Beans有了自己的用户化器时,在构造工具内就可展现出自己的属性表。在定义用户化器时必须要实现java.Beanss.Customizer接口。例如,下面是一个"按钮"Beans的用户化一器:
publicclassOurButtonCustomizer
extendsPanelimplementsCustomizer{
......
/*当实现象OurButtonCustomizer这样的常规属性表时,
一定要在其中实现addProperChangeListener
和removePropertyChangeListener,这样,
构造工具可用这些功能代码为属性事件添加监听者。*/
......
privatePropertyChangeSupportchanges=newPropertyChangeSupport(this);
publicvoidaddPropertyChangeListener(PropertyChangeListenerl){
changes.addPropertyChangeListener(l);
publicvoidremovePropertyChangeListener(PropertyChangeListenerl){
changes.removePropertyChangeListener(l);
}
......
属性编辑器接口(PropertyEditorInterface)
一个JavaBeans可提供PropertyEditor类,为指定的属性创建一个编辑器。这个类必须继承自java.Beanss.PropertyEditorSupport类。构造工具与手写代码的程序员不直接使用这个类,而是在下一小节的BeansInfo中实例化并调用这个类。例:
publicclassMoleculeNameEditorextendsjava.Beanss.PropertyEditorSupport{
publicString[]getTags(){
Stringresule[]={
"HyaluronicAcid","Benzene","buckmisterfullerine",
"cyclohexane","ethane","water"};
returnresule;}
}
上例中是为Tags属性创建了属性编辑器,在构造工具内,可从下拉表格中选择MoleculeName的属性应是"HyaluronicAid"或是"water"。
BeansInfo接口
每个Beans类也可能有与之相关的BeansInfo类,在其中描述了这个Beans在构造工具内出现时的外观。BeansInfo中可定义属性、方法、事件,显示它们的名称,提供简单的帮助说明。例如:
publicclassMoleculeBeansInfoextendsSimpleBeansInfo{
publicPropertyDescriptor[]getPropertyDescriptors(){
try{
PropertyDescriptorpd=newPropertyDescriptor("moleculeName",Molecule.class);
/*通过pd引用了上一节的MoleculeNameEditor类,取得并返回moleculeName属性*/
pd.setPropertyEditorClass(MoleculeNameEditor.class);
PropertyDescriptorresult[]={pd};
returnresult;
}catch(Exceptionex){
System.err.println("MoleculeBeansInfo:unexpectedexeption:"+ex);
returnnull;
}
}
}
JavaBeans持久化
当一个JavaBeans在构造工具内被用户化,并与其它Beans建立连接之后,它的所有状态都应当可被保存,下一次被load进构造工具内或在运行时,就应当是上一次修改完的信息。为了能做到这一点,要把Beans的某些字段的信息保存下来,在定义Beans时要使它实现java.io.Serializable接口。例如:
publicclassButton
implementsjava.io.Serializable{
}
实现了序列化接口的Beans中字段的信息将被自动保存。若不想保存某些字段的信息则可在这些字段前冠以transient或static关键字,transient和static变量的信息是不可被保存的。通常,一个Beans所有公开出来的属性都应当是被保存的,也可有选择地保存内部状态。Beans开发者在修改软件时,可以添加字段,移走对其它类的引用,改变一个字段的private/protected/public状态,这些都不影响类的存储结构关系。然而,当从类中删除一个字段,改变一个变量在类体系中的位置,把某个字段改成transient/static,或原来是transient/static,现改为别的特性时,都将引起存储关系的变化。
JavaBeans的存储格式
JavaBeans组件被设计出来后,一般是以扩展名为jar的Zip格式文件存储,在jar中包含与JavaBeans有关的信息,并以MANIFEST文件指定其中的哪些类是JavaBeans。以jar文件存储的JavaBeans在网络中传送时极大地减少了数据的传输数量,并把JavaBeans运行时所需要的一些资源捆绑在一起,本章主要论述了JavaBeans的一些内部特性及其常规设计方法,参考的是JavaBeans规范1.0A版本。随着世界各大ISV对JavaBeans越来越多的支持,规范在一些细节上还在不断演化,但基本框架不会再有大的变动。
JavaBeans的属性与一般Java程序中所指的属性,或者说与所有面向对象的程序设计语言中对象的属性是一个概念,在程序中的具体体现就是类中的变量。在JavaBeans设计中,按照属性的不同作用又细分为四类:Simple,Index,Bound与Constrained属性。
1.Simple属性
一个简单属性表示一个伴随有一对get/set方法(C语言的过程或函数在Java程序中称为"方法")的变量。属性名与和该属性相关的get/set方法名对应。例如:如果有setX和getX方法,则暗指有一个名为"X"的属性。如果有一个方法名为isX,则通常暗指"X"是一个布尔属性(即X的值为true或false)。例如在下面这个程序中:
publicclassalden1extendsCanvas{
stringourString="Hello";//属性名为ourString,类型为字符串
publicalden1(){ //alden1()是alden1的构造函数,
与C++中构造函数的意义相同
setBackground(Color.red);
setForeground(Color.blue);
}
/*"set"属性*/
publicvoidsetString(StringnewString){
ourString=newString;
}
/*"get"属性*/
publicStringgetString(){
returnourString;
}
}
2.Indexed属性
一个Indexed属性表示一个数组值。使用与该属性对应的set/get方法可取得数组中的数值。该属性也可一次设置或取得整个数组的值。例:
publicclassalden2extendsCanvas{
int[]dataSet={1,2,3,4,5,6};//dataSet是一个indexed属性
publicalden2(){
setBackground(Color.red);
setForeground(Color.blue);
}
/*设置整个数组 */
publicvoidsetDataSet(int[]x){
dataSet=x;
}
/*设置数组中的单个元素值*/
publicvoidsetDataSet(intindex,intx){
dataSet[index]=x;
}
/*取得整个数组值*/
publicint[]getDataSet(){
returndataSet;
}
/*取得数组中的指定元素值*/
publicintgetDataSet(intx){
returndataSet[x];
}
}
3.Bound属性
一个Bound属性是指当该种属性的值发生变化时,要通知其它的对象。每次属性值改变时,这种属性就点火一个PropertyChange事件(在Java程序中,事件也是一个对象)。事件中封装了属性名、属性的原值、属性变化后的新值。这种事件是传递到其它的Beans,至于接收事件的Beans应做什么动作由其自己定义。当PushButton的background属性与Dialog的background属性bind时,若PushButton的background属性发生变化时,Dialog的background属性也发生同样的变化。例:
publicclassalden3extendsCanvas{
StringourString="Hello";
//ourString是一个bound属性
privatePropertyChangeSupportchanges=newPropertyChangeSupport(this);
/**注:Java是纯面向对象的语言,
如果要使用某种方法则必须指明是要使用哪个对象的方法,
在下面的程序中要进行点火事件的操作,
这种操作所使用的方法是在PropertyChangeSupport类中的。
所以上面声明并实例化了一个changes对象,
在下面将使用changes的firePropertyChange方法来点火ourString的属性改变事件。*/
publicvoidsetString(stringnewString){
StringoldString=ourString;
ourString=newString;
/*ourString的属性值已发生变化,于是接着点火属性改变事件*/
changes.firePropertyChange("ourString",oldString,newString);
}
publicStringgetString(){
returnourString;
}
/**以下代码是为开发工具所使用的。
我们不能预知alden3将与哪些其它的Beans组合成为一个应用,
无法预知若alden3的ourString属性发生变化时有哪些其它的组件与此变化有关,
因而alden3这个Beans要预留出一些接口给开发工具,
开发工具使用这些接口,
把其它的JavaBeans对象与alden3挂接。*/
publicvoidaddPropertyChangeListener(PropertyChangeLisenerl){
changes.addPropertyChangeListener(l);
}
publicvoidremovePropertyChangeListener(PropertyChangeListenerl){
changes.removePropertyChangeListener(l);
}
通过上面的代码,
开发工具调用changes的addPropertyChangeListener方法
把其它JavaBeans注册入ourString属性的监听者队列l中,
l是一个Vector数组,可存储任何Java对象。
开发工具也可使用changes的removePropertyChangeListener方法,
从l中注销指定的对象,
使alden3的ourString属性的改变不再与这个对象有关。
当然,当程序员手写代码编制程序时,
也可直接调用这两个方法,
把其它Java对象与alden3挂接。
4.Constrained属性
一个JavaBeans的constrained属性,是指当这个属性的值要发生变化时,与这个属性已建立了某种连接的其它Java对象可否决属性值的改变。constrained属性的监听者通过抛出PropertyVetoException来阻止该属性值的改变。例:下面程序中的constrained属性是PriceInCents。
publicclassJellyBeansextendsCanvas{
privatePropertyChangeSupportchanges=newPropertyChangeSupport(this);
privateVetoableChangeSupportVetos=newVetoableChangeSupport(this);
/*与前述changes相同,
可使用VetoableChangeSupport对象的实例Vetos中的方法,
在特定条件下来阻止PriceInCents值的改变。*/
......
publicvoidsetPriceInCents(intnewPriceInCents)throwsPropertyVetoException{
/*方法名中throwsPropertyVetoException的作用是当有
其它Java对象否决PriceInCents的改变时,
要抛出例外。*/
/*先保存原来的属性值*/
intoldPriceInCents=ourPriceInCents;
/**点火属性改变否决事件*/
vetos.fireVetoableChange("priceInCents",newInteger(OldPriceInCents),
newInteger(newPriceInCents));
/**若有其它对象否决priceInCents的改变,
则程序抛出例外,不再继续执行下面的两条语句,
方法结束。若无其它对象否决priceInCents的改变,
则在下面的代码中把ourPriceIncents赋予新值,
并点火属性改变事件*/
ourPriceInCents=newPriceInCents;
changes.firePropertyChange("priceInCents",
newInteger(oldPriceInCents),
newInteger(newPriceInCents));
}
/**与前述changes相同,
也要为PriceInCents属性预留接口,
使其它对象可注册入PriceInCents否决改变监听者队列中,
或把该对象从中注销
publicvoidaddVetoableChangeListener(VetoableChangeListenerl)
{vetos.addVetoableChangeListener(l);
}
publicvoidremoveVetoableChangeListener(VetoableChangeListenerl){
vetos.removeVetoableChangeListener(l);
}
......
}
从上面的例子中可看到,一个constrained属性有两种监听者:属性变化监听者和否决属性改变的监听者。否决属性改变的监听者在自己的对象代码中有相应的控制语句,在监听到有constrained属性要发生变化时,在控制语句中判断是否应否决这个属性值的改变。
总之,某个Beans的constrained属性值可否改变取决于其它的Beans或者是Java对象是否允许这种改变。允许与否的条件由其它的Beans或Java对象在自己的类中进行定义。
JavaBeans的事件
事件处理是JavaBeans体系结构的核心之一。通过事件处理机制,可让一些组件作为事件源,发出可被描述环境或其它组件接收的事件。这样,不同的组件就可在构造工具内组合在一起,组件之间通过事件的传递进行通信,构成一个应用。从概念上讲,事件是一种在"源对象"和"监听者对象"之间,某种状态发生变化的传递机制。事件有许多不同的用途,例如在Windows系统中常要处理的鼠标事件、窗口边界改变事件、键盘事件等。在Java和JavaBeans中则是定义了一个一般的、可扩充的事件机制,这种机制能够:
对事件类型和传递的模型的定义和扩充提供一个公共框架,并适合于广泛的应用。
与Java语言和环境有较高的集成度。
事件能被描述环境捕获和点火。
能使其它构造工具采取某种技术在设计时直接控制事件,以及事件源和事件监听者之间的联系。
事件机制本身不依赖于复杂的开发工具。特别地,还应当:
能够发现指定的对象类可以生成的事件。
能够发现指定的对象类可以观察(监听)到的事件。
提供一个常规的注册机制,允许动态操纵事件源与事件监听者之间的关系。
不需要其它的虚拟机和语言即可实现。
事件源与监听者之间可进行高效的事件传递。
能完成JavaBeans事件模型与相关的其它组件体系结构事件模型的中立映射。
JavaBeans事件模型的主要构成有:事件从事件源到监听者的传递是通过对目标监听者对象的Java方法调用进行的。对每个明确的事件的发生,都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者(EventListener)接口中,这个接口要继承java.util.EventListener。实现了事件监听者接口中一些或全部方法的类就是事件监听者。伴随着事件的发生,相应的状态通常都封装在事件状态对象中,该对象必须继承自java.util.EventObject。事件状态对象作为单参传递给应响应该事件的监听者方法中。发出某种特定事件的事件源的标识是:遵从规定的设计格式为事件监听者定义注册方法,并接受对指定事件监听者接口实例的引用。有时,事件监听者不能直接实现事件监听者接口,或者还有其它的额外动作时,就要在一个源与其它一个或多个监听者之间插入一个事件适配器类的实例,来建立它们之间的联系。
事件状态对象(EventStateObject)
与事件发生有关的状态信息一般都封装在一个事件状态对象中,这种对象是java.util.EventObject的子类。按设计习惯,这种事件状态对象类的名应以Event结尾。例如:
publicclassMouseMovedExampleEventextendsjava.util.EventObject
{protectedintx,y;
/* 创建一个鼠标移动事件MouseMovedExampleEvent*/
MouseMovedExampleEvent(java.awt.Componentsource,Pointlocation){
super(source);
x=location.x;
y=location.y;
}
/*获取鼠标位置*/
publicPointgetLocation(){
returnnewPoint(x,y);
}}
事件监听者接口(EventListenerInterface)与事件监听者
由于Java事件模型是基于方法调用,因而需要一个定义并组织事件操纵方法的方式。JavaBeans中,事件操纵方法都被定义在继承了java.util.EventListener类的EventListener接口中,按规定,EventListener接口的命名要以Listener结尾。任何一个类如果想操纵在EventListener接口中定义的方法都必须以实现这个接口方式进行。这个类也就是事件监听者。例如:
/*先定义了一个鼠标移动事件对象*/
publicclassMouseMovedExampleEvent
extendsjava.util.EventObject{
//在此类中包含了与鼠标移动事件有关的状态信息
...
}
/*定义了鼠标移动事件的监听者接口*/
interfaceMouseMovedExampleListener
extendsjava.util.EventListener{
/*在这个接口中定义了鼠标移动事件监听者所应支持的方法*/
voidmouseMoved(MouseMovedExampleEventmme);
}
在接口中只定义方法名,
方法的参数和返回值类型。
如:上面接口中的mouseMoved方法的
具体实现是在下面的ArbitraryObject类中定义的。
classArbitraryObjectimplementsMouseMovedExampleListener{
publicvoidmouseMoved(MouseMovedExampleEventmme)
{...}
}
ArbitraryObject就是MouseMovedExampleEvent事件的监听者。
事件监听者的注册与注销
为了各种可能的事件监听者把自己注册入合适的事件源中,建立源与事件监听者间的事件流,事件源必须为事件监听者提供注册和注销的方法。在前面的bound属性介绍中已看到了这种使用过程,在实际中,事件监听者的注册和注销要使用标准的设计格式:
publicvoidadd<ListenerType>(<ListenerType>listener);
publicvoidremove<ListenerType>(<ListenerType>listener);
例如:
首先定义了一个事件监听者接口:
publicinterface
ModelChangedListenerextendsjava.util.EventListener{
voidmodelChanged(EventObjecte);
}
接着定义事件源类:
publicabstractclassModel{
privateVectorlisteners=newVector();//定义了一个储存事件监听者的数组
/*上面设计格式中的<ListenerType>在此处即是下面的ModelChangedListener*/
publicsynchronizedvoidaddModelChangedListener(ModelChangedListenermcl)
{listeners.addElement(mcl);}//把监听者注册入listeners数组中
publicsynchronizedvoidremoveModelChangedListener(ModelChangedListenermcl)
{listeners.removeElement(mcl);//把监听者从listeners中注销
}
/*以上两个方法的前面均冠以synchronized,
是因为运行在多线程环境时,
可能同时有几个对象同时要进行注册和注销操作,
使用synchronized来确保它们之间的同步。
开发工具或程序员使用这两个方法建立源与监听者之间的事件流*/
protectedvoidnotifyModelChanged(){
/**事件源使用本方法通知监听者发生了modelChanged事件*/
Vectorl;
EventObjecte=newEventObject(this);
/*首先要把监听者拷贝到l数组中,
冻结EventListeners的状态以传递事件。
这样来确保在事件传递到所有监听者之前,
已接收了事件的目标监听者的对应方法暂不生效。*/
synchronized(this){
l=(Vector)listeners.clone();
}
for(inti=0;i<l.size();i++){
/*依次通知注册在监听者队列中的每个监听者发生了modelChanged事件,
并把事件状态对象e作为参数传递给监听者队列中的每个监听者*/
((ModelChangedListener)l.elementAt(i)).modelChanged(e);
}
}
}
在程序中可见事件源Model类显式地调用了接口中的modelChanged方法,实际是把事件状态对象e作为参数,传递给了监听者类中的modelChanged方法。
适配类
适配类是Java事件模型中极其重要的一部分。在一些应用场合,事件从源到监听者之间的传递要通过适配类来"转发"。例如:当事件源发出一个事件,而有几个事件监听者对象都可接收该事件,但只有指定对象做出反应时,就要在事件源与事件监听者之间插入一个事件适配器类,由适配器类来指定事件应该是由哪些监听者来响应。
适配类成为了事件监听者,事件源实际是把适配类作为监听者注册入监听者队列中,而真正的事件响应者并未在监听者队列中,事件响应者应做的动作由适配类决定。目前绝大多数的开发工具在生成代码时,事件处理都是通过适配类来进行的。
JavaBeans用户化
JavaBeans开发者可以给一个Beans添加用户化器(Customizer)、属性编辑器(PropertyEditor)和BeansInfo接口来描述一个Beans的内容,Beans的使用者可在构造环境中通过与Beans附带在一起的这些信息来用户化Beans的外观和应做的动作。一个Beans不必都有BeansCustomizer、PrpertyEditor和BeansInfo,根据实际情况,这些是可选的,当有些Beans较复杂时,就要提供这些信息,以Wizard的方式使Beans的使用者能够用户化一个Beans。有些简单的Beans可能这些信息都没有,则构造工具可使用自带的透视装置,透视出Beans的内容,并把信息显示到标准的属性表或事件表中供使用者用户化Beans,前几节提到的Beans的属性、方法和事件名要以一定的格式命名,主要的作用就是供开发工具对Beans进行透视。当然也是给程序员在手写程序中使用Beans提供方便,使他能观其名、知其意。
用户化器接口(CustomizerInterface)
当一个Beans有了自己的用户化器时,在构造工具内就可展现出自己的属性表。在定义用户化器时必须要实现java.Beanss.Customizer接口。例如,下面是一个"按钮"Beans的用户化一器:
publicclassOurButtonCustomizer
extendsPanelimplementsCustomizer{
......
/*当实现象OurButtonCustomizer这样的常规属性表时,
一定要在其中实现addProperChangeListener
和removePropertyChangeListener,这样,
构造工具可用这些功能代码为属性事件添加监听者。*/
......
privatePropertyChangeSupportchanges=newPropertyChangeSupport(this);
publicvoidaddPropertyChangeListener(PropertyChangeListenerl){
changes.addPropertyChangeListener(l);
publicvoidremovePropertyChangeListener(PropertyChangeListenerl){
changes.removePropertyChangeListener(l);
}
......
属性编辑器接口(PropertyEditorInterface)
一个JavaBeans可提供PropertyEditor类,为指定的属性创建一个编辑器。这个类必须继承自java.Beanss.PropertyEditorSupport类。构造工具与手写代码的程序员不直接使用这个类,而是在下一小节的BeansInfo中实例化并调用这个类。例:
publicclassMoleculeNameEditorextendsjava.Beanss.PropertyEditorSupport{
publicString[]getTags(){
Stringresule[]={
"HyaluronicAcid","Benzene","buckmisterfullerine",
"cyclohexane","ethane","water"};
returnresule;}
}
上例中是为Tags属性创建了属性编辑器,在构造工具内,可从下拉表格中选择MoleculeName的属性应是"HyaluronicAid"或是"water"。
BeansInfo接口
每个Beans类也可能有与之相关的BeansInfo类,在其中描述了这个Beans在构造工具内出现时的外观。BeansInfo中可定义属性、方法、事件,显示它们的名称,提供简单的帮助说明。例如:
publicclassMoleculeBeansInfoextendsSimpleBeansInfo{
publicPropertyDescriptor[]getPropertyDescriptors(){
try{
PropertyDescriptorpd=newPropertyDescriptor("moleculeName",Molecule.class);
/*通过pd引用了上一节的MoleculeNameEditor类,取得并返回moleculeName属性*/
pd.setPropertyEditorClass(MoleculeNameEditor.class);
PropertyDescriptorresult[]={pd};
returnresult;
}catch(Exceptionex){
System.err.println("MoleculeBeansInfo:unexpectedexeption:"+ex);
returnnull;
}
}
}
JavaBeans持久化
当一个JavaBeans在构造工具内被用户化,并与其它Beans建立连接之后,它的所有状态都应当可被保存,下一次被load进构造工具内或在运行时,就应当是上一次修改完的信息。为了能做到这一点,要把Beans的某些字段的信息保存下来,在定义Beans时要使它实现java.io.Serializable接口。例如:
publicclassButton
implementsjava.io.Serializable{
}
实现了序列化接口的Beans中字段的信息将被自动保存。若不想保存某些字段的信息则可在这些字段前冠以transient或static关键字,transient和static变量的信息是不可被保存的。通常,一个Beans所有公开出来的属性都应当是被保存的,也可有选择地保存内部状态。Beans开发者在修改软件时,可以添加字段,移走对其它类的引用,改变一个字段的private/protected/public状态,这些都不影响类的存储结构关系。然而,当从类中删除一个字段,改变一个变量在类体系中的位置,把某个字段改成transient/static,或原来是transient/static,现改为别的特性时,都将引起存储关系的变化。
JavaBeans的存储格式
JavaBeans组件被设计出来后,一般是以扩展名为jar的Zip格式文件存储,在jar中包含与JavaBeans有关的信息,并以MANIFEST文件指定其中的哪些类是JavaBeans。以jar文件存储的JavaBeans在网络中传送时极大地减少了数据的传输数量,并把JavaBeans运行时所需要的一些资源捆绑在一起,本章主要论述了JavaBeans的一些内部特性及其常规设计方法,参考的是JavaBeans规范1.0A版本。随着世界各大ISV对JavaBeans越来越多的支持,规范在一些细节上还在不断演化,但基本框架不会再有大的变动。
发表评论
-
LinkedHashMap
2016-01-13 09:18 672public static void main(Strin ... -
计算星期几,本周的开始结束日期,上一周的开始结束日期
2015-11-04 15:03 1303package com.yinhe.util; imp ... -
java pattern matcher字符串替换
2015-10-28 13:56 898<div class="iteye-blog ... -
jfreechart实现仪表盘dashbord
2015-08-24 17:13 845package com.htcf.dashbord; ... -
java中byte,String,InputStream之间的转换
2012-09-20 17:09 21142import java.io.ByteArrayInpu ... -
StringBuffer清空方法,效率最高
2012-08-10 11:42 1817StringBuffer清空方法大致有4种: Stri ... -
日期大小写转换
2012-07-23 10:53 1935import java.util.Calendar; i ... -
web.xml不认<taglib>解决办法:
2012-07-11 15:24 970在web.xml不认<taglib>解决办法: ... -
VO,PO,TO,BO,POJO,DAO解释
2012-03-20 14:47 1493O/R Mapping:Object Relation ... -
Java 推算日期(计算距今多少年,多少月,多少天的日期)
2011-10-24 16:13 4907import java.text.SimpleDateForm ... -
jdk与jre的区别
2011-07-05 11:31 1215今天突然有朋友问, ... -
JAVA混淆 RetroGuard (转)
2011-06-17 13:28 64211、 下载并将retroguard.jar拷贝 ... -
JavaScript检测上传文件类型
2011-04-22 16:41 1874很实用的一个JS代码,判断一个上传表单允许上传的文件类型,扩展 ... -
比较全的文件操作(创建,删除,复制.文件,文件夹,复制图片)
2011-03-21 18:57 1324package com.potevio.zjhs.util; ... -
id,pid,数据库递归调用展示树形菜单的示例
2011-03-01 15:11 7429public class TreeDAO{ ... -
dtree 树形菜单(checkbox默认选中)
2011-01-24 15:07 5892采用dtree实现树形菜单展示,并有默认checkbox的选中 ... -
Java处理带返回值的存储过程Procedure (SQL Server)
2010-12-27 11:06 4820package com.zjx.test; import ... -
学JAVA很好的一个资源网站
2010-11-19 15:24 1355http://www.verycd.com/topics/93 ... -
某人关于不重复登录的简单处理说明
2010-11-02 13:39 13361.用的是servlet的监听器:(1)用的是HttpSess ... -
java获取资源文件(**.properties)
2010-11-01 15:57 1115import java.io.IOException; im ...
相关推荐
### JavaBean属性命名规范 JavaBean是一种遵循特定编码标准的Java类,主要用于封装数据或表示简单的数据载体。在JavaBean中,属性的命名规范是非常重要的,因为它直接影响到代码的可读性和可维护性,同时也会影响到...
以下是对四种不同类型的JavaBean属性的详细说明: 1. **Simple 属性** Simple属性是最基础的属性类型,它包含一对getter和setter方法,用于获取和设置属性的值。属性名称通常与getter和setter方法的名字相对应。...
下面我们将详细探讨这三个类的使用方法以及它们在字符串到JavaBean属性赋值中的应用。 首先,`BeanUtils`是Apache Commons BeanUtils库中的核心类,提供了大量与JavaBean操作相关的功能。其中,`BeanUtils....
### JavaBean 属性详解 JavaBean 是一种遵循特定编码规范的 Java 类,广泛应用于 Java 应用程序中,尤其是在服务器端应用中。JavaBean 的核心是它的属性,这些属性不仅体现了面向对象编程中的封装特性,还为外部...
本项目为Apache Commons子项目——commons-beanutils的核心源码,专注于利用Java反射机制高效处理JavaBean属性。该项目结构丰富,包含331个文件,涵盖295个Java源文件、14个XML文件、5个文本文件等,旨在为Java开发...
Java 基础之 JavaBean 属性命名规范问题 JavaBean 属性命名规范问题是 Java 开发中一个重要的知识点。JavaBean 是一种特殊的 Java 类,它遵循特定的命名规范,以便于其他 Java 类可以正确地访问和操作它的属性。...
可以 将 数据库表中字段转为相应的 javaBean 对象 很方便的 生产bean
Java Bean属性命名规范问题分析
1. 属性(properties):JavaBean 提供了高层次的属性概念,属性在 JavaBean 中不只是传统的面向对象的概念里的属性,它同时还得到了属性读取和属性写入的 API 的支持。 2. 方法(method):JavaBean 中的方法就是...
2. 在JSP页面中通过EL(表达式语言)和JSTL标签访问JavaBean属性。 3. 学习如何在Spring框架中使用JavaBean作为模型对象。 4. 实现属性变更监听器(PropertyChangeListener),以响应属性值的改变。 这个"JavaBean...
1. 属性(Properties):JavaBean 的属性是指 JavaBean 中的变量或字段,它可以是基本数据类型如 int、double 等,也可以是对象类型如 String、Array 等。 2. 方法(Method):JavaBean 的方法是指 JavaBean 中的...
问题描述:存在一个JavaBean,它包含以下几种可能的属性: 1.boolean/Boolean 2.int/Integer 3.String 4.double/Double ...只需要设置带有getXxx/isXxx/setXxx方法的属性, 非JavaBean属性不设置, 请用代码实现.
2. **理解JavaBean属性命名约定**:JavaBean属性遵循驼峰命名法,即首个单词的首字母小写,后续单词首字母大写。例如,`firstName`对应的getter方法为`getFirstName()`。 3. **审查JavaBean代码**:仔细检查...
3. 遵循JavaBeans规范:如果JavaBean属性发生变化,应该提供`PropertyChangeSupport`来支持属性改变事件的发布。 二、JavaBean在JSP中的应用 JSP(JavaServer Pages)是一种动态网页技术,它可以与JavaBean结合使用...
"minimalcode-convert"是一个Java项目,专注于提供一个简约的JavaBean属性转换系统。这个工具的设计目标是简化Java对象之间的数据转换过程,特别是在处理不同数据结构间的映射时,如JSON到Java对象、Java对象到...
- 在访问JavaBean属性前检查对象是否已实例化。 - 遵守JavaBean的命名规范,保证getter和setter方法与属性名称匹配。 - 对于可能被多个线程访问的JavaBean,确保其线程安全或使用线程局部变量。 通过以上讨论,我们...
- `param`: 从请求参数中获取值来设置JavaBean属性。 - `value`: 直接指定的属性值。 总结 JSP和JavaBean的结合为Web应用开发提供了强大的功能。`<jsp:useBean>`、`<jsp:setProperty>`和`<jsp:getProperty>`这三个...
JavaBean 的属性可以是任意类型,并且一个 JavaBean 可以拥有多个属性。为了方便访问这些属性,通常会为每个属性提供对应的 getter 和 setter 方法。 - **Getter 方法**:以 `get` 开头,后面紧跟属性名,首字母...
2. **设置和获取JavaBean属性**: - 设置JavaBean的属性值通常使用`<jsp:setProperty>`标签,例如: ```jsp ``` - 这里,`name`属性对应于JavaBean的引用名,`property`属性指定了要设置的属性名,`value`属性...
jox库的优点在于其简洁的API和对JavaBean属性的自动映射,使得开发人员能够快速地进行数据交换。 5. **注意事项** - 确保JavaBean的属性名称与XML元素名称相匹配,因为jox库默认使用属性名称作为XML元素的标签。 ...