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數據
}