<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 13.18 可視編程和Beans 迄今為止,我們已看到Java對創建可重復使用的代碼片工作而言是多么的有價值。“最大限度地可重復使用”的代碼單元擁有類,因為它包含一個緊密結合在一起的單元特性(字段)和單元動作(方法),它們可以直接經過混合或通過繼承被重復使用。 繼承和多態態性是面向對象編程的精華,但在大多數情況下當我們創建一個應用程序時,我們真正最想要的恰恰是我們最需要的組件。我們希望在我們的設計中設置這些部件就像電子工程師在電路板上創造集成電路塊一樣(在使用Java的情況下,就是放到WEB頁面上)。這似乎會成為加快這種“模塊集合”編制程序方法的發展。 “可視化編程”最早的成功——非常的成功——要歸功于微軟公司的Visual Basic(VB,可視化Basic語言),接下來的第二代是Borland公司Delphi(一種客戶/服務器數據庫應用程序開發工具,也是Java Beans設計的主要靈感)。這些編程工具的組件的像征就是可視化,這是不容置疑的,因為它們通常展示一些類型的可視化組件,例如:一個按慣或一個TextField。事實上,可視化通常表現為組件可以非常精確地訪問運行中程序。因此可視化編程方法的一部分包含從一個調色盤從拖放一個組件并將它放置到我們的窗體中。應用程序創建工具像我們所做的一樣編寫程序代碼,該代碼將導致正在運行的程序中的組件被創建。 簡單地拖放組件到一個窗體中通常不足以構成一個完整的程序。一般情況下,我們需要改變組件的特性,例如組件的色彩,組件的文字,組件連結的數據庫,等等。特性可以參照屬性在編程時進行修改。我們可以在應用程序構建工具中巧妙處置我們組件的屬性,并且當我們創建程序時,構建數據被保存下來,所以當該程序被啟動時,數據能被重新恢復。 到如今,我們可能習慣于使用對象的多個特性,這也是一個動作集合。在設計時,可視化組件的動作可由事件部分地代表,意味著“任何事件都可以發生在組件上”。通常,由我們決定想發生的事件,當一個事件發生時,對所發生的事件連接代碼。 這是關鍵性的部分:應用程序構建工具可以動態地詢問組件(利用映象)以發現組件支持的事件和屬件。一旦它知道它們的狀態,應用程序構建工具就可以顯示組件的屬性并允許我們修改它們的屬性(當我們構建程序時,保存它們的狀態),并且也顯示這些事件。一般而言,我們做一些事件像雙擊一個事件以及應用程序構建工具創建一個代碼并連接到事件上。當事件發生時,我們不得不編寫執行代碼。應用程序構建工具累計為我們做了大量的工作。結果我們可以注意到程序看起來像它所假定的那樣運行,并且依賴應用程序構建工具去為我們管理連接的詳細資料。可視化的編程工具如此成功的原因是它們明顯加快構建的應用程序的處理過程——當然,用戶接口作為應用程序的一部分同樣的好。 ## 13.18.1 什么是Bean 在經細節處理后,一個組件在類中被獨特的具體化,真正地成為一塊代碼。關鍵的爭議在于應用程序構建工具發現組件的屬性和事件能力。為了創建一個VB組件,程序開發者不得不編寫正確的同時也是復雜煩瑣的代碼片,接下來由某些協議去展現它們的事件和屬性。Delphi是第二代的可視化編程工具并且這種開發語言主動地圍繞可視化編程來設計因此它更容易去創建一個可視化組件。但是,Java帶來了可視化的創作組件做為Java Beans最高級的“裝備”,因為一個Bean就是一個類。我們不必再為制造任何的Bean而編寫一些特殊的代碼或者使用特殊的編程語言。事實上,我們唯一需要做的是略微地修改我們對我們方法命名的辦法。方法名通知應用程序構建工具是否是一個屬性,一個事件或是一個普通的方法。 在Java的文件中,命名規則被錯誤地曲解為“設計模式”。這十分的不幸,因為設計模式(參見第16章)惹來不少的麻煩。命名規則不是設計模式,它是相當的簡單: (1) 因為屬性被命名為`xxx`,我們代表性的創建兩個方法:`getXxx()`和`setXxx()`。注意`get`或`set`后的第一個字母小寫以產生屬性名。`get`和`set`方法產生同樣類型的參數。`set`和`get`的屬性名和類型名之間沒有關系。 (2) 對于布爾邏輯型屬性,我們可以使用上面的`get`和`set`方法,但我們也可以用`is`代替 `get`。 (3) Bean的普通方法不適合上面的命名規則,但它們是公用的。 (4)對于事件,我們使用`listener`(接收器)方法。這種方法完全同我們看到過的方法相同:(`addFooBarListener(FooBarListener)`和`removeFooBarListener(FooBarListener)`方法用來處理`FooBar`事件。大多數時候內建的事件和接收器會滿足我們的需要,但我們可以創建自己的事件和接收器接口。 上面的第一點回答了一個關于我們可能注意到的從Java 1.0到Java 1.1的改變的問題:一些方法的名字太過于短小,顯然改寫名字毫無意義。現在我們可以看到為了制造Bean中的特殊的組件,大多數的這些修改不得不適合于`get`和`set`命名規則。 現在,我們已經可以利用上面的這些指導方針去創建一個簡單的Bean: ``` //: Frog.java // A trivial Java Bean package frogbean; import java.awt.*; import java.awt.event.*; class Spots {} public class Frog { private int jumps; private Color color; private Spots spots; private boolean jmpr; public int getJumps() { return jumps; } public void setJumps(int newJumps) { jumps = newJumps; } public Color getColor() { return color; } public void setColor(Color newColor) { color = newColor; } public Spots getSpots() { return spots; } public void setSpots(Spots newSpots) { spots = newSpots; } public boolean isJumper() { return jmpr; } public void setJumper(boolean j) { jmpr = j; } public void addActionListener( ActionListener l) { //... } public void removeActionListener( ActionListener l) { // ... } public void addKeyListener(KeyListener l) { // ... } public void removeKeyListener(KeyListener l) { // ... } // An "ordinary" public method: public void croak() { System.out.println("Ribbet!"); } } ///:~ ``` 首先,我們可看到Bean就是一個類。通常,所有我們的字段會被作為專用,并且可以接近的唯一辦法是通過方法。緊接著的是命名規則,屬性是`jump`,`color`,`jumper`,`spots`(注意這些修改是在第一個字母在屬性名的情況下進行的)。雖然內部確定的名字同最早的三個例子的屬性名一樣,在`jumper`中我們可以看到屬性名不會強迫我們使用任何特殊的內部可變的名字(或者,真的擁有一些內部的可變的屬性名)。 Bean事件的引用是`ActionEvent`和`KeyEvent`,這是根據有關接收器的`add`和`remove`命名方法得出的。最后我們可以注意到普通的方法`croak()`一直是Bean的一部分,僅僅是因為它是一個公共的方法,而不是因為它符合一些命名規則。 ## 13.18.2 用Introspector提取BeanInfo 當我們拖放一個Bean的調色板并將它放入到窗體中時,一個Bean的最關鍵的部分的規則發生了。應用程序構建工具必須可以創建Bean(如果它是默認的構造器的話,它就可以做)然后,在此范圍外訪問Bean的源代碼,提取所有的必要的信息以創立屬性表和事件處理器。 解決方案的一部分在11章結尾部分已經顯現出來:Java 1.1版的映象允許一個匿名類的所有方法被發現。這完美地解決了Bean的難題而無需我們使用一些特殊的語言關鍵字像在其它的可視化編程語言中所需要的那樣。事實上,一個主要的原因是映象增加到Java 1.1版中以支持Beans(盡管映象同樣支持對象串聯和遠程方法調用)。因為我們可能希望應用程序構建工具的開發者將不得不映象每個Bean并且通過它們的方法搜索以找到Bean的屬性和事件。 這當然是可能的,但是Java的研制者們希望為每個使用它的用戶提供一個標準的接口,而不僅僅是使Bean更為簡單易用,不過他們也同樣提供了一個創建更復雜的Bean的標準方法。這個接口就是`Introspector`類,在這個類中最重要的方法靜態的`getBeanInfo()`。我們通過一個類處理這個方法并且`getBeanInfo()`方法全面地對類進行查詢,返回一個我們可以進行詳細研究以發現其屬性、方法和事件的`BeanInfo`對象。 通常我們不會留意這樣的一些事物——我們可能會使用我們大多數的現成的Bean,并且我們不需要了解所有的在底層運行的技術細節。我們會簡單地拖放我們的Bean到我們窗體中,然后配置它們的屬性并且為事件編寫處理器。無論如何它都是一個有趣的并且是有教育意義的使用`Introspector`來顯示關于Bean信息的練習,好啦,閑話少說,這里有一個工具請運行它(我們可以在`forgbean`子目錄中找到它): ``` //: BeanDumper.java // A method to introspect a Bean import java.beans.*; import java.lang.reflect.*; public class BeanDumper { public static void dump(Class bean){ BeanInfo bi = null; try { bi = Introspector.getBeanInfo( bean, java.lang.Object.class); } catch(IntrospectionException ex) { System.out.println("Couldn't introspect " + bean.getName()); System.exit(1); } PropertyDescriptor[] properties = bi.getPropertyDescriptors(); for(int i = 0; i < properties.length; i++) { Class p = properties[i].getPropertyType(); System.out.println( "Property type:\n " + p.getName()); System.out.println( "Property name:\n " + properties[i].getName()); Method readMethod = properties[i].getReadMethod(); if(readMethod != null) System.out.println( "Read method:\n " + readMethod.toString()); Method writeMethod = properties[i].getWriteMethod(); if(writeMethod != null) System.out.println( "Write method:\n " + writeMethod.toString()); System.out.println("===================="); } System.out.println("Public methods:"); MethodDescriptor[] methods = bi.getMethodDescriptors(); for(int i = 0; i < methods.length; i++) System.out.println( methods[i].getMethod().toString()); System.out.println("======================"); System.out.println("Event support:"); EventSetDescriptor[] events = bi.getEventSetDescriptors(); for(int i = 0; i < events.length; i++) { System.out.println("Listener type:\n " + events[i].getListenerType().getName()); Method[] lm = events[i].getListenerMethods(); for(int j = 0; j < lm.length; j++) System.out.println( "Listener method:\n " + lm[j].getName()); MethodDescriptor[] lmd = events[i].getListenerMethodDescriptors(); for(int j = 0; j < lmd.length; j++) System.out.println( "Method descriptor:\n " + lmd[j].getMethod().toString()); Method addListener = events[i].getAddListenerMethod(); System.out.println( "Add Listener Method:\n " + addListener.toString()); Method removeListener = events[i].getRemoveListenerMethod(); System.out.println( "Remove Listener Method:\n " + removeListener.toString()); System.out.println("===================="); } } // Dump the class of your choice: public static void main(String[] args) { if(args.length < 1) { System.err.println("usage: \n" + "BeanDumper fully.qualified.class"); System.exit(0); } Class c = null; try { c = Class.forName(args[0]); } catch(ClassNotFoundException ex) { System.err.println( "Couldn't find " + args[0]); System.exit(0); } dump(c); } } ///:~ ``` `BeanDumper.dump()`是一個可以做任何工作的方法。首先它試圖創建一個`BeanInfo`對象,如果成功地調用`BeanInfo`的方法,就產生關于屬性、方法和事件的信息。在`Introspector.getBeanInfo()`中,我們會注意到有一個另外的參數。由它來通知`Introspector`訪問繼承體系的地點。在這種情況下,它在分析所有對象方法前停下,因為我們對看到那些并不感興趣。 因為屬性,`getPropertyDescriptors()`返回一組的屬性描述符號。對于每個描述符號我們可以調用`getPropertyType()`方法徹底的通過屬性方法發現類的對象。這時,我們可以用`getName()`方法得到每個屬性的假名(從方法名中提取),`getname()`方法用`getReadMethod()`和`getWriteMethod()`完成讀和寫的操作。最后的兩個方法返回一個可以真正地用來調用在對象上調用相應的方法方法對象(這是映象的一部分)。對于公共方法(包括屬性方法),`getMethodDescriptors()`返回一組方法描述字符。每一個我們都可以得到相當的方法對象并可以顯示出它們的名字。 對于事件而言,`getEventSetDescriptors()`返回一組事件描述字符。它們中的每一個都可以被查詢以找出接收器的類,接收器類的方法以及增加和刪除接收器的方法。`BeanDumper`程序打印出所有的這些信息。 如果我們調用`BeanDumper`在`Frog`類中,就像這樣: ``` java BeanDumper frogbean.Frog ``` 它的輸出結果如下(已刪除這兒不需要的額外細節): ``` class name: Frog Property type: Color Property name: color Read method: public Color getColor() Write method: public void setColor(Color) ==================== Property type: Spots Property name: spots Read method: public Spots getSpots() Write method: public void setSpots(Spots) ==================== Property type: boolean Property name: jumper Read method: public boolean isJumper() Write method: public void setJumper(boolean) ==================== Property type: int Property name: jumps Read method: public int getJumps() Write method: public void setJumps(int) ==================== Public methods: public void setJumps(int) public void croak() public void removeActionListener(ActionListener) public void addActionListener(ActionListener) public int getJumps() public void setColor(Color) public void setSpots(Spots) public void setJumper(boolean) public boolean isJumper() public void addKeyListener(KeyListener) public Color getColor() public void removeKeyListener(KeyListener) public Spots getSpots() ====================== Event support: Listener type: KeyListener Listener method: keyTyped Listener method: keyPressed Listener method: keyReleased Method descriptor: public void keyTyped(KeyEvent) Method descriptor: public void keyPressed(KeyEvent) Method descriptor: public void keyReleased(KeyEvent) Add Listener Method: public void addKeyListener(KeyListener) Remove Listener Method: public void removeKeyListener(KeyListener) ==================== Listener type: ActionListener Listener method: actionPerformed Method descriptor: public void actionPerformed(ActionEvent) Add Listener Method: public void addActionListener(ActionListener) Remove Listener Method: public void removeActionListener(ActionListener) ==================== ``` 這個結果揭示出了`Introspector`在從我們的Bean產生一個`BeanInfo`對象時看到的大部分內容。我們可注意到屬性的類型和它們的名字是相互獨立的。請注意小寫的屬性名。(當屬性名開頭在一行中有超過不止的大寫字母,這一次程序就不會被執行。)并且請記住我們在這里所見到的方法名(例如讀和與方法)真正地從一個可以被用來在對象中調用相關方法的方法對象中產生。 通用方法列表包含了不相關的事件或者屬性,例如`croak()`。列表中所有的方法都是我們可以有計劃的為Bean調用,并且應用程序構建工具可以選擇列出所有的方法,當我們調用方法時,減輕我們的任務。 最后,我們可以看到事件在接收器中完全地分析研究它的方法、增加和減少接收器的方法。基本上,一旦我們擁有`BeanInfo`,我們就可以找出對Bean來說任何重要的事物。我們同樣可以為Bean調用方法,即使我們除了對象外沒有任何其它的信息(此外,這也是映象的特點)。 ## 13.18.3 一個更復雜的Bean 接下的程序例子稍微復雜一些,盡管這沒有什么價值。這個程序是一張不論鼠標何時移動都圍繞它畫一個小圓的,并且一個動作接收器被激活。畫布。當按下鼠標鍵時,我們可以改變的屬性是圓的大小,除此之外還有被顯示文字的色彩,大小,內容。`BangBean`同樣擁有它自己的`addActionListener()`和`removeActionListener()`方法,因此我們可以附上自己的當用戶單擊在`BangBean`上時會被激活的接收器。這樣,我們將能夠確認可支持的屬性和事件: ``` //: BangBean.java // A graphical Bean package bangbean; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; public class BangBean extends Canvas implements Serializable { protected int xm, ym; protected int cSize = 20; // Circle size protected String text = "Bang!"; protected int fontSize = 48; protected Color tColor = Color.red; protected ActionListener actionListener; public BangBean() { addMouseListener(new ML()); addMouseMotionListener(new MML()); } public int getCircleSize() { return cSize; } public void setCircleSize(int newSize) { cSize = newSize; } public String getBangText() { return text; } public void setBangText(String newText) { text = newText; } public int getFontSize() { return fontSize; } public void setFontSize(int newSize) { fontSize = newSize; } public Color getTextColor() { return tColor; } public void setTextColor(Color newColor) { tColor = newColor; } public void paint(Graphics g) { g.setColor(Color.black); g.drawOval(xm - cSize/2, ym - cSize/2, cSize, cSize); } // This is a unicast listener, which is // the simplest form of listener management: public void addActionListener ( ActionListener l) throws TooManyListenersException { if(actionListener != null) throw new TooManyListenersException(); actionListener = l; } public void removeActionListener( ActionListener l) { actionListener = null; } class ML extends MouseAdapter { public void mousePressed(MouseEvent e) { Graphics g = getGraphics(); g.setColor(tColor); g.setFont( new Font( "TimesRoman", Font.BOLD, fontSize)); int width = g.getFontMetrics().stringWidth(text); g.drawString(text, (getSize().width - width) /2, getSize().height/2); g.dispose(); // Call the listener's method: if(actionListener != null) actionListener.actionPerformed( new ActionEvent(BangBean.this, ActionEvent.ACTION_PERFORMED, null)); } } class MML extends MouseMotionAdapter { public void mouseMoved(MouseEvent e) { xm = e.getX(); ym = e.getY(); repaint(); } } public Dimension getPreferredSize() { return new Dimension(200, 200); } // Testing the BangBean: public static void main(String[] args) { BangBean bb = new BangBean(); try { bb.addActionListener(new BBL()); } catch(TooManyListenersException e) {} Frame aFrame = new Frame("BangBean Test"); aFrame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); aFrame.add(bb, BorderLayout.CENTER); aFrame.setSize(300,300); aFrame.setVisible(true); } // During testing, send action information // to the console: static class BBL implements ActionListener { public void actionPerformed(ActionEvent e) { System.out.println("BangBean action"); } } } ///:~ ``` 最重要的是我們會注意到`BangBean`執行了這種串聯化的接口。這意味著應用程序構建工具可以在程序設計者調整完屬性值后利用串聯為`BangBean`貯藏所有的信息。當Bean作為運行的應用程序的一部分被創建時,那些被貯藏的屬性被重新恢復,因此我們可以正確地得到我們的設計。 我們能看到通常同Bean一起運行的所有的字段都是專用的——允許只能通過方法來訪問,通常利用“屬性”結構。 當我們注視著`addActionListener()`的簽名時,我們會注意到它可以產生出一個`TooManyListenerException`(太多接收器異常)。這個異常指明它是一個單一的類型的,意味著當事件發生時,它只能通知一個接收器。一般情況下,我們會使用具有多種類型的事件,以便一個事件通知多個的接收器。但是,那樣會陷入直到下一章我們才能準備好的結局中,因此這些內容會被重新回顧(下一個標題是“Java Beans 的重新回顧”)。單一類型的事件回避了這個難題。 當我們按下鼠標鍵時,文字被安入`BangBean`中間,并且如果動作接收器字段存在,它的`actionPerformed()`方法就被調用,創建一個新的`ActionEvent`對象在處理過程中。無論何時鼠標移動,它的新座標將被捕捉,并且畫布會被重畫(像我們所看到的抹去一些畫布上的文字)。 `main()`方法增加了允許我們從命令行中測試程序的功能。當一個Bean在一個開發環境中,`main()`方法不會被使用,但擁有它是絕對有益的,因為它提供了快捷的測試能力。無論何時一個`ActionEvent`發生,`main()`方法都將創建了一個幀并安置了一個`BangBean`在它里面,還在`BangBean`中附上了一個簡單的動作接收器以打印到控制臺。當然,一般來說應用程序構建工具將創建大多數的Bean的代碼。當我們通過`BeanDumper`或者安放`BangBean`到一個可激活Bean的開發環境中去運行`BangBean`時,我們會注意到會有很多額外的屬性和動作明顯超過了上面的代碼。那是因為`BangBean`從畫布中繼承,并且畫布就是一個Bean,因此我們看到它的屬性和事件同樣的合適。 ## 13.18.4 Bean的封裝 在我們可以安放一個Bean到一個可激活Bean的可視化構建工具中前,它必須被放入到標準的Bean容器里,也就是包含Bean類和一個表示“這是一個Bean”的清單文件的JAR(Java ARchive,Java文件)文件中。清單文件是一個簡單的緊隨事件結構的文本文件。對于`BangBean`而言,清單文件就像下面這樣: ``` Manifest-Version: 1.0 Name: bangbean/BangBean.class Java-Bean: True ``` 其中,第一行指出清單文件結構的版本,這是SUN公司在很久以前公布的版本。第二行(空行忽略)對文件命名為`BangBean.class`。第三行表示“這個文件是一個Bean”。沒有第三行,程序構建工具不會將類作為一個Bean來認可。 唯一難以處理的部分是我們必須肯定`Name:`字段中的路徑是正確的。如果我們回顧`BangBean.java`,我們會看到它在`package bangbean`(因為存放類路徑的子目錄稱為`bangbean`)中,并且這個名字在清單文件中必須包括封裝的信息。另外,我們必須安放清單文件在我們封裝路徑的根目錄上,在這個例子中意味著安放文件在`bangbean`子目錄中。這之后,我們必須從同一目錄中調用Jar來作為清單文件,如下所示: ``` jar cfm BangBean.jar BangBean.mf bangbean ``` 這個例子假定我們想產生一個名為`BangBean.jar`的文件并且我們將清單放到一個稱為`BangBean.mf`文件中。 我們可能會想“當我編譯`BangBean.java`時,產生的其它類會怎么樣呢?”哦,它們會在`bangbean`子目錄中被中止,并且我們會注意到上面`jar`命令行的最后一個參數就是`bangbean`子目錄。當我們給`jar`子目錄名時,它封裝整個的子目錄到`jar`文件中(在這個例子中,包括`BangBean.java`的源代碼文件——對于我們自己的Bean我們可能不會去選擇包含源代碼文件。)另外,如果我們改變主意,解開打包的JAR文件,我們會發現我們清單文件并不在里面,但`jar`創建了它自己的清單文件(部分根據我們的文件),稱為`MAINFEST.MF`并且安放它到`META-INF`子目錄中(代表“meta-information”)。如果我們打開這個清單文件,我們同樣會注意到`jar`為每個文件加入數字簽名信息,其結構如下: ``` Digest-Algorithms: SHA MD5 SHA-Digest: pDpEAG9NaeCx8aFtqPI4udSX/O0= MD5-Digest: O4NcS1hE3Smnzlp2hj6qeg== ``` 一般來說,我們不必擔心這些,如果我們要做一些修改,可以修改我們的原始的清單文件并且重新調用`jar`以為我們的Bean創建了一個新的JAR文件。我們同樣也可以簡單地通過增加其它的Bean的信息到我們清單文件來增加它們到JAR文件中。 值得注意的是我們或許需要安放每個Bean到它自己的子目錄中,因為當我們創建一個JAR文件時,分配JAR應用目錄名并且JAR放置子目錄中的任何文件到JAR文件中。我們可以看到`Frog`和`BangBean`都在它們自己的子目錄中。 一旦我們將我們的Bean正確地放入一個JAR文件中,我們就可以攜帶它到一個可以激活Bean的編程環境中使用。使用這種方法,我們可以從一種工具到另一種工具間交替變換,但SUN公司為Java Beans提供了免費高效的測試工具在它們的“Bean Development Kit,Bean開發工具”(BDK)稱為`beanbox`。(我們可以從`www.javasoft.com`處下載。)在我們啟動`beanbox`前,放置我們的Bean到`beanbox`中,復制JAR文件到BDK的`jars`子目錄中。 ## 13.18.5 更復雜的Bean支持 我們可以看到創建一個Bean顯然多么的簡單。在程序設計中我們幾乎不受到任何的限制。Java Bean的設計提供了一個簡單的輸入點,這樣可以提高到更復雜的層次上。這些高層次的問題超出了這本書所要討論的范圍,但它們會在此做簡要的介紹。我們可以在`http://java.sun.com/beans`上找到更多的詳細資料。 我們增加更加復雜的程序和它的屬性到一個位置。上面的例子顯示一個獨特的屬性,當然它也可能代表一個數組的屬性。這稱為索引屬性。我們簡單地提供一個相應的方法(再者有一個方法名的命名規則)并且`Introspector`認可索引屬性,因此我們的應用程序構建工具相應的處理。 屬性可以被捆綁,這意味著它們將通過`PropertyChangeEvent`通知其它的對象。其它的對象可以隨后根據對Bean的改變選擇修改它們自己。 屬性可以被束縛,這意味著其它的對象可以在一個屬性的改變不能被接受時,拒絕它。其它的對象利用一個`PropertyChangeEvent`來通知,并且它們產生一個`ProptertyVetoException`去阻止修改的發生,并恢復為原來的值。 我們同樣能夠改變我們的Bean在設計時的被描繪成的方法: (1) 我們可以為我們特殊的Bean提供一個定制的屬性表。這個普通的屬性表將被所有的Bean所使用,但當我們的Bean被選擇時,它會自動地調用這張屬性表。 (2) 我們可以為一個特殊的屬性創建一個定制的編輯器,因此普通的屬性表被使用,但當我們指定的屬性被調用時,編輯器會自動地被調用。 (3)我們可以為我們的Bean提供一個定制的`BeanInfo`類,產生的信息不同于由`Introspector`默認產生的。 (4) 它同樣可能在所有的`FeatureDescriptors`中改變`expert`的開關模式,以辨別基本特征和更復雜的特征。 ## 13.18.6 Bean更多的知識 另外有關的爭議是Bean不能被編址。無論何時我們創建一個Bean,都希望它會在一個多線程的環境中運行。這意味著我們必須理解線程的出口,我們將在下一章中介紹。我們會發現有一段稱為“Java Beans的回顧”的節會注意到這個問題和它的解決方案。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看