<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    飛翔的起點

    從這里出發

    導航

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    統計

    常用鏈接

    留言簿(5)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    #

    Collection 概述

            線性表,鏈表,哈希表是常用的數據結構,在進行Java開發時,JDK已經為我們提供了一系列相應的類來實現基本的數據結構。這些類均在java.util包中。本文試圖通過簡單的描述,向讀者闡述各個類的作用以及如何正確使用這些類。

        Collection
        ├List
        │├LinkedList
        │├ArrayList
        │└Vector
        │ └Stack
        └Set
        Map
        ├Hashtable
        ├HashMap
        └WeakHashMap

        Collection接口
          Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java  SDK不提供直接繼承自Collection的類,Java  SDK提供的類都是繼承自Collection的“子接口”如List和Set。
          所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用于創建一個空的Collection,有一個Collection參數的構造函數用于創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。后一個構造函數允許用戶復制一個Collection。
          如何遍歷Collection中的每一個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:
            Iterator  it  =  collection.iterator();  //  獲得一個迭代子
            while(it.hasNext())  {
              Object  obj  =  it.next();  //  得到下一個元素
            }
          由Collection接口派生的兩個接口是List和Set。

        List接口
          List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。
        和下面要提到的Set不同,List允許有相同的元素。
          除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向后遍歷。
          實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。

        LinkedList類
          LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
          注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
            List  list  =  Collections.synchronizedList(new  LinkedList(...));

        ArrayList類
          ArrayList實現了可變大小的數組。

            它允許所有元素,包括null。ArrayList沒有同步。
        size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。
          每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法并沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
          和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

        Vector類
          Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和ArrayList創建的Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該異常。

        Stack  類
          Stack繼承自Vector,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建后是空棧。

        Set接口
          Set是一種不包含重復的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。
          很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重復的元素。
          請注意:必須小心操作可變對象(Mutable  Object)。如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。

        Map接口
          請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。

        Hashtable類
          Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。
          添加數據使用put(key,  value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。
        Hashtable通過initial  capacity和load  factor兩個參數調整性能。通常缺省的load  factor  0.75較好地實現了時間和空間的均衡。增大load  factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。
        使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:
            Hashtable  numbers  =  new  Hashtable();
            numbers.put(“one”,  new  Integer(1));
            numbers.put(“two”,  new  Integer(2));
            numbers.put(“three”,  new  Integer(3));
          要取出一個數,比如2,用相應的key:
            Integer  n  =  (Integer)numbers.get(“two”);
            System.out.println(“two  =  ”  +  n);
          由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。
          如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。
          Hashtable是同步的。

        HashMap類
          HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null  value和null  key。,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load  factor過低。

        WeakHashMap類
          WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。

    posted @ 2008-04-17 16:22 forgood 閱讀(137) | 評論 (0)編輯 收藏

    newInstance和new的差別

    在初始化一個類,生成一個實例的時候,newInstance()方法和new關鍵字除了一個是方法,一個是關鍵字外,最主要有什么區別?它們的區別在于創建對象的方式不一樣,前者是使用類加載機制,后者是創建一個新類。那么為什么會有兩種創建對象方式?這主要考慮到軟件的可伸縮、可擴展和可重用等軟件設計思想。

        Java中工廠模式經常使用newInstance()方法來創建對象,因此從為什么要使用工廠模式上可以找到具體答案。 例如:

        class c = Class.forName(“Example”);

        factory = (ExampleInterface)c.newInstance();


        其中ExampleInterface是Example的接口,可以寫成如下形式:

        String className = "Example";

        class c = Class.forName(className);

        factory = (ExampleInterface)c.newInstance();


        進一步可以寫成如下形式:

        String className = readfromXMlConfig;//從xml 配置文件中獲得字符串

        class c = Class.forName(className);

        factory = (ExampleInterface)c.newInstance();


        上面代碼已經不存在Example的類名稱,它的優點是,無論Example類怎么變化,上述代碼不變,甚至可以更換Example的兄弟類Example2 , Example3 , Example4……,只要他們繼承ExampleInterface就可以。


        從JVM的角度看,我們使用關鍵字new創建一個類的時候,這個類可以沒有被加載。但是使用newInstance()方法的時候,就必須保證:1、這個類已經加載;2、這個類已經連接了。而完成上面兩個步驟的正是Class的靜態方法forName()所完成的,這個靜態方法調用了啟動類加載器,即加載java API的那個加載器。


        現在可以看出,newInstance()實際上是把new這個方式分解為兩步,即首先調用Class加載方法加載某個類,然后實例化。 這樣分步的好處是顯而易見的。我們可以在調用class的靜態加載方法forName時獲得更好的靈活性,提供給了一種降耦的手段。


        最后用最簡單的描述來區分new關鍵字和newInstance()方法的區別:

        newInstance: 弱類型。低效率。只能調用無參構造。

        new: 強類型。相對高效。能調用任何public構造。

     

    posted @ 2008-04-16 15:18 forgood 閱讀(188) | 評論 (0)編輯 收藏

    EJB3.0概述

    引言  
      期待以久的EJB3.0規范在最近發布了它的初稿。在本文中將對新的規范進行一個概要性的介紹,包括新增的元數據支持,EJBQL的修改,實體Bean模型訪問bean上下文的新方法和運行時環境等等。作者還討論了EJB在未來要作出的調整以及EJB3.0與其他開發規范之間的關系。

      開始

      無論如何由于EJB的復雜性使之在J2EE架構中的表現一直不是很好。EJB大概是J2EE架構中唯一一個沒有兌現其能夠簡單開發并提高生產力的組建。EJB3.0規范正嘗試在這方面作出努力以減輕其開發的復雜性。EJB3.0減輕了開發人員進行底層開發的工作量,它取消或最小化了很多(以前這些是必須實現)回調方法的實現,并且降低了實體Bean及O/R映射模型的復雜性。

      在本文中,我首先會介紹EJB3.0中幾個主要的改變。它對進一步深入了解EJB3.0是非常重要的。隨后,我會從更高的層面來描述已經被提交到EJB3.0規范中的細節,并一個個的講解新的規范中的改變:實體Bean,O/R映射模型,實體關系模型和EJB QL(EJB查詢語言)等等。

      背景

      EJB3.0中兩個重要的變更分別是:使用了Java5中的程序注釋工具和基于Hibernate的O/R映射模型。

      Java5中的元數據工具

      Java5(以前叫J2SE1.5或Tiger)中加入了一種新的程序注釋工具。通過這個工具你可以自定義注釋標記,通過這些自定義標記來注釋字段、方法、類等等。這些注釋并不會影響程序的語義,但是可以通過工具(編譯時或運行時)來解釋這些標記并產生附加的內容(比如部署描述文件),或者強制某些必須的運行時行為(比如EJB組件的狀態特性)。注釋的解析可以通過源文件的解析(比如編譯器或這IDE工具)或者使用Java5中的APIs反射機制。注釋只能被定義在源代碼層。由于所有被提交到EJB3.0草案中的注釋標記都有一個運行時的RetentionPolicy,因此會增加類文件占用的存儲空間,但這卻給容器制造商和工具制造商帶來了方便。

      Hibernate

      目前Hibernate非常受歡迎,它是開發源代碼的Java O/R映射框架,目的是把開發人員從繁瑣的數據持久化編程中解脫出來。它也有一個標準的HQL(Hibernate 查詢語言)語言,你可以在新的EJB QL中看到它的影子。Hibernate在處理如數據查詢、更新、連接池、事務處理、實體關系處理等方面非常簡單。


        概覽

      在已經提交的EJB3.0規范中主要涉及兩個方面的改變:

      1. 一套以注釋為基礎的EJB編程模型,再加上EJB2.1中定義的通過部署描述符和幾個接口定義的應用程序行為。

      2. 新的實體Bean持久化模型,EJBQL也有許多重要的改變。

      還有一些有關上述的提議,比如:一個新的客戶端編程模型,業務接口的使用以及實體Bean的生命周期。請注意EJB2.1編程模型(包括部署描述符和home/remote接口)仍然是有效的。新的簡化模型并沒有完全取代EJB2.1模型。

      EJB注釋

      EJB規范組織一個重要的目標是減輕原始代碼的數量,并且他們為此給出了一個完美而簡介的辦法。在EJB3.0的里,任何類型的企業級Bean只是一個加了適當注釋的簡單Java對象(POJO)。注釋可以用于定義bean的業務接口、O/R映射信息、資源引用信息,效果與在EJB2.1中定義部署描述符和接口是一樣的。在EJB3.0中部署描述符不再是必須的了;home接口也沒有了,你也不必實現業務接口(容器可以為你完成這些事情)。

      比如,你可以使用@Stateless注釋標記類把Java類聲明為一個無狀態會話bean。對于有狀態會話bean來說,@Remove注釋可以用來標記一個特定的方法,通過這個注釋來說明在調用這個方法之后bean的實例將被清除掉。

      為了減少描述組件的說明信息,規范組織還采納了由異常進行配置(configuration-by-exception)的手段,意思是你可以為所有的注釋提供一個明確的缺省值,這樣多數常規信息就可以據此推斷得出。

      新的持久化模型

      新的實體bean也是一個加了注釋的簡單Java對象(POJO)。一旦它被EntityManager訪問它就成為了一個持久化對象,并且成為了持久化上下文(context)的一部分。一個持久化上下文與一個事務上下文是松耦合的;嚴格的講,它隱含的與一個事務會話共存。

      實體關系也是通過注釋來定義的,O/R映射也是,并提供幾種不同的數據庫規范操作,在EJB2.1中這些要通過開發人員自己的設計模式或者其它技術來完成的(比如,自增長主鍵策略)。

      深入研究

      現在是時候詳細了解EJB3.0草案了。讓我們開始探討所有EJB中四種企業級bean,并看看他們在新的規范中是什么樣子。

      無狀態會話bean

      在EJB3.0規范中,寫一個無狀態會話bean(SLSB)只需要一個簡單的Java文件并在類層加上@Stateless注釋就可以了。這個bean可以擴展javax.ejb.SessionBean接口,但這些不是必須的。

      一個SLSB不再需要home接口,沒有哪類EJB再需要它了。Bean類可以實現業務接口也可以不實現它。如果沒有實現任何業務接口,業務接口會由任意public的方法產生。如果只有幾個業務方法會被暴露在業務接口中,這些方法可以使用@BusinessMethod注釋。缺省情況下所有產生的接口都是local(本地)接口,你也可以使用@Remote注釋來聲明這個接口為remote(遠程)接口。

      下面的幾行代碼就可以定義一個HelloWorldbean了。而在EJB2.1中同樣的bean至少需要兩個接口,一個實現類和幾個空的實現方法,再加上部署描述符。  

      mport javax.ejb.*;

      

      /**

      * A stateless session bean requesting that a remote business

      * interface be generated for it.

      */

      @Stateless

      @Remote

      public class HelloWorldBean {

       public String sayHello() {

        return "Hello World!!!";

       }

      }

      

      有狀態會話bean

      除了幾個SFSB的特別說明之外,有狀態會話bean(SFSB)和SLSB一樣精簡:

      1) 一個SFSB應該有一個方法來初始化自己(在EJB2.1中是通過ejbCreate()來實現的)。在EJB3.0的規范中建議這些初始化操作可以通過自定義方法完成,并把他們暴露在業務接口中。在使用這個bean之前由客戶端來調用相應的初始化方法。目前規范組織就是否提供一個注釋來標記某個方法用于初始化還存在爭議。

      2) Bean的提供者可以用@Remove注釋來標記任何SFSB的方法,以說明這個方法被調用之后bean的實例將被移除。同樣,規范組織仍然在討論是否要有一種機制來處理這種特殊的情況,即當這個方法出現異常的情況下bean的實例是否被移除。

      下面是對以上問題我個人的觀點:

      1) 是否應該有一個注釋來標明一個方法進行初始化呢?我的觀點是――應該有,這樣容器就可以在調用其他方法之前至少調用一個方法來進行初始化。這不僅可以避免不必要的錯誤(由于沒有調用初始化方法)而且可以使容器更明確的判斷是否可以重用SFSB實例。我暫且把這個問題放一放,規范組織只考慮為一個方法提供一個注釋來聲明它是一個初始化方法。

      2) 對于第二個問題我的觀點也是肯定的。這有利于Bean的提供者合客戶端程序對其進行控制。只有一個遺留的問題:那就是一旦調用這個方法失敗,是否能移除這個bean 的實例?答案是不能,但是它將會在會話結束的時候被移除。

      消息驅動Bean

      消息驅動Bean是唯一一種必須實現一個業務接口的Bean。這個接口指出bean支持的是哪一種消息系統。對于以JMS為基礎的MDB來說,這個接口是javax.jms.MessageListener。注意MDB業務接口不是一個真正意義上的業務接口,它只是一個消息接口。

      實體Bean

      1) 實體Bean使用@Entity注釋來標記,所有實體bean中的屬性/字段不必使用@Transient注釋來標記。實體bean的持久化字段可以通過JavaBean-style機制或者聲明為public/protected字段來實現。

      2) 實體bean可以使用助手類來描述其狀態,但是這些類的實例并沒有持久化唯一性(persistent identity)的特性(即,唯一標識這個bean的字段等),實際上這些助手類與他們的實體bean實例是緊密結合的;并且這些對象還是以非共享方式來訪問實體對象的。

      實體關聯

      EJB3.0同時支持Bean之間雙向的合單向的關聯,它們可以是一對一、一對多、多對一或者是多對多的關聯。然而雙向關聯的兩端還要分為自身端(owning side)和對方端(inverse side)不同的端。自身端負責向數據庫通告關聯的變更。對于多對多的關聯自身端必須明確的聲明。實際上對方端通過isInverse=true進行注釋(由此自身端就不必說明了而是由另一段推斷出)。看來上面的描述,規范組織還能說讓EJB變的簡單了嗎?

      O/R映射

      EJB3.0中的O/R映射模型也有了重要的改變,它從原來的abstract-persistence-schema-based變成了現在的Hibernate-inspired模式。盡管目前規范組織還在就此進行討論但是一個明確的模型將會出現在下一個版本的草案中。

      舉例來說,O/R映射模型將通過bean類中的注釋來聲明。而且此方法還會指出對應的具體表和字段。O/R映射模型提供了一套自有的SQL;而且除了提供一些基本的SQL外還支持某些高層開發的功能。比如,有一個通過@Column注釋聲明的字段columnDefinition,那么可以寫這樣的SQL:columnDefinition="BLOB NOT NULL" 

    客戶端程序模型

      一個EJB客戶端可以通過@Inject注釋以一種“注入”的方式獲得一個bean的業務接口引用。你也可以使用另一個注釋@javax.ejb.EJBContext.lookup()來完成上面的操作,但是規范中沒有告訴我們一個普通的Java客戶端怎樣獲得一個Bean的實例,因為這個普通的Java客戶端是運行在一個客戶端容器中,它無法訪問@javax.ejb.EJBContex對象。現在還有另外一種機制來完成上面的工作那就是使用一個超級上下文環境對象:@javax.ejb.Context()。但是規范中沒有指出該如何在客戶端中使用這個對象。

      EJB QL

      EJB QL可以通過@NamedQuery來注釋。這個注釋有兩個成員屬性分別是name和queryString.一旦定義了這些屬性,就可以通過EntityManager.createNamedQuery(name)來指向這個查詢。你也可以創建一個標準的JDBC風格的查詢并使用EntityManager.createQuery(ejbqlString)或EntityManager.createNativeQuery(nativeSqlString)(這個方法用于執行一個本地查詢)來執行查詢。

      EJB QL有兩個地方可以定義其參數。javax.ejb.Query接口提供了定義參數、指向查詢、更新數據等等方法。下面是一個EJBQL指向查詢的例子:

      .. ..

      @NamedQuery(

      name="findAllCustomersWithName",

      queryString="SELECT c FROM Customer c WHERE c.name LIKE :custName"

      )

      .. ..

      @Inject public EntityManager em;

      customers = em.createNamedQuery("findAllCustomersWithName")

      .setParameter("custName", "Smith")

      .listResults();

      

      下面列出了一些EJB QL的增強特性:

      1) 支持批量更新和刪除。

      2) 直接支持內連接和外連接。FETCH JOIN運行你指出關聯的實體,Order可以指定只查詢某個字段。

      3) 查詢語句可以返回一個以上的結果值。實際上,你可以返回一個依賴的類比如下面這樣:  

      SELECT new CustomerDetails(c.id, c.status, o.count)

      FROM Customer c JOIN c.orders o

      WHERE o.count > 100  

      4) 支持group by 和having。

      5) 支持where子句的嵌套子查詢。

      在提交的EJB3.0草案中,EJB QL與標準SQL非常的接近。實際上規范中甚至直接支持本地的SQL(就像我們上面提到的那樣)。這一點對某些程序員來說也許有些不是很清楚,我們將在下面進行更詳細的講解。

      多樣性

      方法許可(Method permissions)可以通過@MethodPermissions或@Unchecked注釋來聲明;同樣的,事務屬性也可以通過@TransactionAttribute注釋來聲明。規范中仍然保留資源引用和資源環境引用。這些一樣可以通過注釋來聲明,但是有一些細微的差別。比如,上下文(context)環境要通過注入工具控制。容器根據bean對外部環境引用自動初始化一個適當的已經聲明的實例變量。比如,你可以象下面這樣獲得一個數據源(DataSource):  

      @Resource(name="myDataSource") //Type is inferred from variable

      public DataSource customerDB;

      在上面的例子中如果你不指定引用資源的名稱(name)那么其中的customerDB會被認為是默認值。當所有的引用屬性都可得到時,@Injec注釋就可以這樣寫:  

      @Inject public DataSource customerDB;

      容器負責在運行時初始化customerDB數據源實例。部署人員必須在此之前在容器中定義好這些資源屬性。

      更好的消息是:那些以前必須檢測的異常將一去不復返。你可以聲明任意的應用程序異常,而不必在再拋出或捕獲其他類似CreateException和FinderException這樣的異常。容器會拋出封裝在javax.ejb.EJBException中的系統級異常或者只在必要時候拋出IllegalArgumentException或IllegalStateException異常。

    EJB文件處理模式

      在我們結束本節之前,讓我的快速的瀏覽一下容器提供商在EJB處理模式方面可能的變更。規范中對此并沒有明確的表態,但我可以想到至少兩種模式。

      1) 一種辦法是首先利用EJB文件生成類似于EJB2.1部署模式的文件(包括必要的接口和部署描述符)然后再用類似于EJB2.1的方式來部署這個EJB組件。當然,這樣產生的部署描述符可能并不標準但是它可以解決同一個容器對EJB2.1和EJB3.0兼容的問題。  

      2) 另一種方法是一種類似于JSP托放的部署模式。你可以把一個EJB文件放到一個預先定義的目錄下,然后容器會識別這個EJB并處理它,然后部署并使之可以使用。這種方法可以建立于上面那種方法之上,在支持反復部署時有很大的幫助。考慮到部署的簡單性也是EJB3.0規范的目的之一,我真誠的希望在下一個草案出來時能夠確定一個模式(至少能有一個非正式的)。

      你有什么想法?

      EJB3.0規范的制定正在有序的進行,為了使EJB的開發變得更加容易,EJB規范組織作出的努力是有目共睹的。就像他們說的那樣,一切對會變得簡單,但做到這一點并不容易。目前已經定義了50個注釋標記(還有幾個將在下一個草案中發布),每一個都有自己的缺省規則和其他的操作。當然,我真的不希望EJB3.0變成EJB2.1的一個翻版"EJB 3.0 = EJB 2.1 for dummies"(希望這個等式不要成立)。最后,我還是忍不住要提一些我自己的觀點:

      1) 首先,規范確實使反復部署變得容易了,并且有一個簡單的模式來訪問運行時環境。我還是覺得home接口應該放棄。

      2) 在早期的EJB規范中,實體bean用于映射一個持久化存儲。理論上(也許只是理論上)可能需要把實體bean映射到一個遺留的EIS(enterprise information system)系統中。出于將來擴展的考慮這樣作是有好處的,并且可以使更多的業務數據模型采用實體bean。也因此其伴隨的復雜性使得實體bean不被看好。在本次提交的草案中,一個實體bean只是一個數據庫的映射。并且是基于非抽象持久化模式和簡單的數據訪問模式的更加簡單開發。

      3) 我對模型變更持保留態度,我認為在EJB中包含SQL腳本片斷并不是個好注意。一些開發人員完全反對包含某些“SQL片段(SQLness)”(比如@Table 和 @Column注釋)。我的觀點是這些SQLness是好的,據此我們可以清楚的知道我們到底要數據庫作些什么。但是某些SQL段我看來并不是很好,比如columnDefinition="BLOB NOT NULL",這使得EJB代碼和SQL之間的耦合太過緊密了。

      4) 盡管對于本地SQL的支持看似很誘人,其實在EJB代碼中嵌入SQL是一個非常糟糕的主意。當然,有些辦法可以避免在EJB中硬編碼SQL,但是這應該在規范中說明,而不能是某些開發人員自己定義的模式。

      5) 假設@Table注釋只用于類。在運行時通過@Table注釋的name屬性定義的表名稱將必須對應一個實際的數據庫表。規范對此應該給予清楚的說明和一致的模式。

      6) 規范還需要更清楚的說明客戶端編程模型,尤其是普通java客戶端。規范中所有的參考都假設或者隱含的使用EJB客戶端。而且規范中對客戶端的向后兼容方面也沒有給出明確的說法。

      7) Transient注釋應該重新命名以避免和已有的transient關鍵字發生沖突。事實上,在這一點上我們更樂于稍微的背離一下configuration-by-exception原則并且定義一個@Persistent注釋來明確的定義持久化字段。@Persistent注釋可以僅僅是一個標記注釋或者它可以有幾個屬性來關聯O/R映射注釋。

      與其他規范的關聯

      目前可能影響到EJB3.0的JSR有JSR175(java語言元數據工具)和JSR181(Java Web服務元數據)

      JSR175已經初步完成并且不會和EJB3.0有太大的沖突;但是JSR181與EJB3.0有兩個關聯的地方:

      1) Web service接口:EJB規范將采用一種機制適應JSR181以便可以把一個bean實現為一個Web service并告訴Web service如何被客戶端調用。

      2) JSR 181計劃采用不同的機制來處理安全問題。在早期的規范中EJB建議使用一個一致的機制(MethodPermissions),但是JSR 181計劃使用一個稍微不同的方式(SecurityRoles和SecurityIdentity注釋)。同樣的RunAs注釋的定義也存在這些許差別。這一問題還在解決中最終會在J2EE層的規范中維持其一致性。

      在J2EE 1.5中的一些開發規范可能與EJB3.0有關聯。除了上面說到的幾個關聯之外現在沒有其他的開發規范與EJB3.0有沖突。

      結束語

      在使EJB的開發變得簡單高效之前,我們還有很長一段路要走。規范組織在降低EJB的開發難度方面起了個好頭。O/R映射模型的提議還處在早期階段,規范組織正在完善它。我希望它不要太復雜也不要與SQL過分的耦合。讓我們不要只是停留在期望、希望、思考和請求中:提出你的想法并把你的建議發送給規范組織ejb3-feedback@sun.com。JCP并不是很民主的組織,但是你的建議一定是有價值的。

    posted @ 2008-04-16 14:49 forgood 閱讀(158) | 評論 (0)編輯 收藏

    設計模式概述

         摘要:         Design Patterns: Elements of Reusable Object-Oriented Software(即后述《設計模式》一書),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。這幾位...  閱讀全文

    posted @ 2008-04-16 14:46 forgood 閱讀(344) | 評論 (0)編輯 收藏

    面向對象主要的五種編程原則

       單一職責原則SRP:Single Responsibility Principle
        開放封閉原則OCP:Open-Close Principle
        Liskov替換原則LSP:Liskov Substitution Principle
        依賴倒置原則DIP:Dependency Invertion Principle
        接口隔離原則ISP:Interface Separate Principle

        在面向對象設計中,如何通過很小的設計改變就可以應對設計需求的變化,這是令設計者極為關注的問題。為此不少OO先驅提出了很多有關面向對象的設計原則用于指導OO的設計和開發。下面是幾條與類設計相關的設計原則。

        1.開閉原則(the Open Closed Principle OCP)
           一個模塊在擴展性方面應該是開放的而在更改性方面應該是封閉的。因此在進行面向對象設計時要盡量考慮接口封裝機制、抽象機制和多態技術。該原則同樣適合 于非面向對象設計的方法,是軟件工程設計方法的重要原則之一。我們以收音機的例子為例,講述面向對象的開閉原則。我們收聽節目時需要打開收音機電源,對準 電臺頻率和進行音量調節。但是對于不同的收音機,實現這三個步驟的細節往往有所不同。比如自動收縮電臺的收音機和按鈕式收縮在操作細節上并不相同。因此, 我們不太可能針對每種不同類型的收音機通過一個收音機類來實現(通過重載)這些不同的操作方式。但是我們可以定義一個收音機接口,提供開機、關機、增加頻 率、降低頻率、增加音量、降低音量六個抽象方法。不同的收音機繼承并實現這六個抽象方法。這樣新增收音機類型不會影響其它原有的收音機類型,收音機類型擴 展極為方便。此外,已存在的收音機類型在修改其操作方法時也不會影響到其它類型的收音機。

        2.替換原則 (the Liskov Substitution Principle LSP)
          子類應當可以替換父類并出現在父類能夠出現的任何地方。這個原則是Liskov于1987年提出的設計原則。它同樣可以從Bertrand Meyer 的DBC (Design by Contract) 的概念推出。
          我們以學生為例,夜校生為學生的子類,因此在任何學生可以出現的地方,夜校生均可出現。這個例子有些牽強,一個能夠反映這個原則的例子時圓和橢圓,圓是橢圓的一個特殊子類。因此任何出現橢圓的地方,圓均可以出現。但反過來就可能行不通。
          運用替換原則時,我們盡量把類B設計為抽象類或者接口,讓C類繼承類B(接口B)并實現操作A和操作B,運行時,類C實例替換B,這樣我們即可進行新類的擴展(繼承類B或接口B),同時無須對類A進行修改。

        3.依賴原則 (the Dependency Inversion Principle DIP)
          在進行業務設計時,與特定業務有關的依賴關系應該盡量依賴接口和抽象類,而不是依賴于具體類。具體類只負責相關業務的實現,修改具體類不影響與特定業務有關的依賴關系。
          在結構化設計中,我們可以看到底層的模塊是對高層抽象模塊的實現(高層抽象模塊通過調用底層模塊),這說明,抽象的模塊要依賴具體實現相關的模塊,底層模塊的具體實現發生變動時將會嚴重影響高層抽象的模塊,顯然這是結構化方法的一個"硬傷"。
          面向對象方法的依賴關系剛好相反,具體實現類依賴于抽象類和接口。
          為此,我們在進行業務設計時,應盡量在接口或抽象類中定義業務方法的原型,并通過具體的實現類(子類)來實現該業務方法,業務方法內容的修改將不會影響到運行時業務方法的調用。

        4.接口分離原則(the Interface Segregation Principle ISP)
            采用多個與特定客戶類有關的接口比采用一個通用的涵蓋多個業務方法的接口要好。
          ISP原則是另外一個支持諸如COM等組件化的使能技術。缺少ISP,組件、類的可用性和移植性將大打折扣。
          這個原則的本質相當簡單。如果你擁有一個針對多個客戶的類,為每一個客戶創建特定業務接口,然后使該客戶類繼承多個特定業務接口將比直接加載客戶所需所有方法有效。

        以上四個原則是面向對象中常常用到的原則。此外,除上述四原則外,還有一些常用的經驗諸如類結構層次以三到四層為宜、類的職責明確化(一個類對應一個具體職 責)等可供我們在進行面向對象設計參考。但就上面的幾個原則看來,我們看到這些類在幾何分布上呈現樹型拓撲的關系,這是一種良好、開放式的線性關系、具有 較低的設計復雜度。一般說來,在軟件設計中我們應當盡量避免出現帶有閉包、循環的設計關系,它們反映的是較大的耦合度和設計復雜化。

    posted @ 2008-04-16 14:39 forgood 閱讀(247) | 評論 (0)編輯 收藏

    關于存儲過程(一)

    oracle 存儲過程的基本語法

     

     

    1.基本結構
    CREATE OR REPLACE PROCEDURE 存儲過程名字
    (
        參數1 IN NUMBER,
        參數2 IN NUMBER
    ) IS
    變量1 INTEGER :=0;
    變量2 DATE;
    BEGIN

    END 存儲過程名字

    2.SELECT INTO STATEMENT
      將select查詢的結果存入到變量中,可以同時將多個列存儲多個變量中,必須有一條
      記錄,否則拋出異常(如果沒有記錄拋出NO_DATA_FOUND)
      例子:
      BEGIN
      SELECT col1,col2 into 變量1,變量2 FROM typestruct where xxx;
      EXCEPTION
      WHEN NO_DATA_FOUND THEN
          xxxx;
      END;
      ...

    3.IF 判斷
      IF V_TEST=1 THEN
        BEGIN
           do something
        END;
      END IF;

    4.while 循環
      WHILE V_TEST=1 LOOP
      BEGIN
     XXXX
      END;
      END LOOP;

    5.變量賦值
      V_TEST := 123;

    6.用for in 使用cursor
      ...
      IS
      CURSOR cur IS SELECT * FROM xxx;
      BEGIN
     FOR cur_result in cur LOOP
      BEGIN
       V_SUM :=cur_result.列名1+cur_result.列名2
      END;
     END LOOP;
      END;

    7.帶參數的cursor
      CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
      OPEN C_USER(變量值);
      LOOP
     FETCH C_USER INTO V_NAME;
     EXIT FETCH C_USER%NOTFOUND;
        do something
      END LOOP;
      CLOSE C_USER;

    8.用pl/sql developer debug
      連接數據庫后建立一個Test WINDOW
      在窗口輸入調用SP的代碼,F9開始debug,CTRL+N單步調試

    9、注意事項
     1.在oracle中,數據表別名不能加as,如:

    select a.appname from appinfo a;-- 正確
    select a.appname from appinfo as a;-- 錯誤
     也許,是怕和oracle中的存儲過程中的關鍵字as沖突的問題吧

    2.在存儲過程中,select某一字段時,后面必須緊跟into,如果select整個記錄,利用游標的話就另當別論了。

      select af.keynode into kn from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 有into,正確編譯
      select af.keynode from APPFOUNDATION af where af.appid=aid and af.foundationid=fid;-- 沒有into,編譯報錯,提示:Compilation 
      Error: PLS-00428: an INTO clause is expected in this SELECT statement

    3.在利用select...into...語法時,必須先確保數據庫中有該條記錄,否則會報出"no data found"異常。

       可以在該語法之前,先利用select count(*) from 查看數據庫中是否存在該記錄,如果存在,再利用select...into...

    4.在存儲過程中,別名不能和字段名稱相同,否則雖然編譯可以通過,但在運行階段會報錯

     select keynode into kn from APPFOUNDATION where appid=aid and foundationid=fid;-- 正確運行
    select af.keynode into kn from APPFOUNDATION af where af.appid=appid and af.foundationid=foundationid;-- 運行階段報錯,提示
    ORA-01422:exact fetch returns more than requested number of rows

    5.在存儲過程中,關于出現null的問題

    假設有一個表A,定義如下:
    create table A(
    id 
    varchar2(50primary key not null,
    vcount 
    number(8not null,
    bid 
    varchar2(50not null -- 外鍵 
    );
    如果在存儲過程中,使用如下語句:
    select sum(vcount) into fcount from A where bid='xxxxxx';
    如果A表中不存在bid="xxxxxx"的記錄,則fcount=null(即使fcount定義時設置了默認值,如:fcount number(8):=0依然無效,fcount還是會變成null),這樣以后使用fcount時就可能有問題,所以在這里最好先判斷一下:
    if fcount is null then
        fcount:
    =0;
    end 
    if;
    這樣就一切ok了。

    6.Hibernate調用oracle存儲過程

            this.pnumberManager.getHibernateTemplate().execute(
                    
    new HibernateCallback() {
                        
    public Object doInHibernate(Session session)
                                
    throws HibernateException, SQLException {
                            CallableStatement cs 
    = session
                                    .connection()
                                    .prepareCall(
    "{call modifyapppnumber_remain(?)}");
                            cs.setString(
    1, foundationid);
                            cs.execute();
                            
    return null;
                        }

                    }
    );

    posted @ 2008-04-14 15:57 forgood 閱讀(174) | 評論 (0)編輯 收藏

    關于oracle的一些問題

    刪除重復記錄:

                           

    辦法一:
    DELETE FROM TAB1 A
    WHERE A.ROWID > ( SELECT MIN(B.ROWID) FROM TAB1 B WHERE A.字段=B.字段 );
    其中子查詢中的“WHERE A.字段=B.字段”用來寫明重復條件。

                           
    ——這一辦法在數據記錄超過10萬時一般都會變得很慢。

    辦法二:
    --建立臨時表,--清空原表,--插回原表,如下例:
    create table temp_emp as (select distinct * from employee) ;
    truncate table employee;
    insert into employee select * from temp_emp;

                           
    ——這一辦法適用于較大的表的情況。因為是塊操作,對應于大表效率會好很多。

                           

    posted @ 2006-09-11 13:34 K 閱讀(39) | 評論 (0)編輯

    ORACLE 常用的SQL語法和數據對象

    一.數據控制語句 (DML) 部分

      1.INSERT (往數據表里插入記錄的語句)

      INSERT INTO 表名(字段名1, 字段名2, ……) VALUES ( 值1, 值2, ……);
      INSERT INTO 表名(字段名1, 字段名2, ……) SELECT (字段名1, 字段名2, ……) FROM 另外的表名;

      字符串類型的字段值必須用單引號括起來, 例如: ’GOOD DAY’
      如果字段值里包含單引號’ 需要進行字符串轉換, 我們把它替換成兩個單引號''. 字符串類型的字段值超過定義的長度會出錯, 最好在插入前進行長度校驗.

      日期字段的字段值可以用當前數據庫的系統時間SYSDATE, 精確到秒或者用字符串轉換成日期型函數TO_DATE(‘2001-08-01’,’YYYY-MM-DD’) TO_DATE()還有很多種日期格式, 可以參看ORACLE DOC. 年-月-日 小時:分鐘:秒 的格式YYYY-MM-DD HH24:MI:SS

      INSERT時最大可操作的字符串長度小于等于4000個單字節, 如果要插入更長的字符串, 請考慮字段用CLOB類型,方法借用ORACLE里自帶的DBMS_LOB程序包.

      INSERT時如果要用到從1開始自動增長的序列號, 應該先建立一個序列號CREATE SEQUENCE 序列號的名稱 (最好是表名+序列號標記) INCREMENT BY 1 START WITH 1
      MAXVALUE 99999 CYCLE NOCACHE;
      其中最大的值按字段的長度來定, 如果定義的自動增長的序列號 NUMBER(6) , 最大值為999999
      INSERT 語句插入這個字段值為: 序列號的名稱.NEXTVAL

      2.DELETE (刪除數據表里記錄的語句)

      DELETE FROM表名 WHERE 條件;

      注意:刪除記錄并不能釋放ORACLE里被占用的數據塊表空間. 它只把那些被刪除的數據塊標成unused.

      如果確實要刪除一個大表里的全部記錄, 可以用 TRUNCATE 命令, 它可以釋放占用的數據塊表空間
      TRUNCATE TABLE 表名;
      此操作不可回退.

      3.UPDATE (修改數據表里記錄的語句)

      UPDATE表名 SET 字段名1=值1, 字段名2=值2, …… WHERE 條件;

      如果修改的值N沒有賦值或定義時, 將把原來的記錄內容清為NULL, 最好在修改前進行非空校驗; 值N超過定義的長度會出錯, 最好在插入前進行長度校驗..

      注意事項:
      A. 以上SQL語句對表都加上了行級鎖,確認完成后, 必須加上事物處理結束的命令 COMMIT 才能正式生效, 否則改變不一定寫入數據庫里. 如果想撤回這些操作, 可以用命令 ROLLBACK 復原.

      B. 在運行INSERT, DELETE 和 UPDATE 語句前最好估算一下可能操作的記錄范圍, 應該把它限定在較小 (一萬條記錄) 范圍內,. 否則ORACLE處理這個事物用到很大的回退段. 程序響應慢甚至失去響應. 如果記錄數上十萬以上這些操作, 可以把這些SQL語句分段分次完成,
      其間加上COMMIT 確認事物處理.
    二.數據定義 (DDL) 部分

      1.CREATE (創建表, 索引, 視圖, 同義詞, 過程, 函數, 數據庫鏈接等)

      ORACLE常用的字段類型有
      CHAR 固定長度的字符串
      VARCHAR2 可變長度的字符串
      NUMBER(M,N) 數字型M是位數總長度, N是小數的長度
      DATE 日期類型

      創建表時要把較小的不為空的字段放在前面, 可能為空的字段放在后面創建表時可以用中文的字段名, 但最好還是用英文的字段名

      創建表時可以給字段加上默認值, 例如 DEFAULT SYSDATE這樣每次插入和修改時, 不用程序操作這個字段都能得到動作的時間

      創建表時可以給字段加上約束條件
      例如 不允許重復 UNIQUE, 關鍵字 PRIMARY KEY

      2.ALTER (改變表, 索引, 視圖等)

      改變表的名稱
      ALTER TABLE 表名1 TO 表名2;

      在表的后面增加一個字段
      ALTER TABLE表名 ADD 字段名 字段名描述;

      修改表里字段的定義描述
      ALTER TABLE表名 MODIFY字段名 字段名描述;

      給表里的字段加上約束條件
      ALTER TABLE 表名 ADD CONSTRAINT 約束名 PRIMARY KEY (字段名);
      ALTER TABLE 表名 ADD CONSTRAINT 約束名 UNIQUE (字段名);

      把表放在或取出數據庫的內存區
      ALTER TABLE 表名 CACHE;
      ALTER TABLE 表名 NOCACHE;

      3.DROP (刪除表, 索引, 視圖, 同義詞, 過程, 函數, 數據庫鏈接等)

      刪除表和它所有的約束條件
      DROP TABLE 表名 CASCADE CONSTRAINTS;

      4.TRUNCATE (清空表里的所有記錄, 保留表的結構)

      TRUNCATE 表名;
     
    ORACLE 常用的SQL語法和數據對象
    作者:網絡 佚名   更新時間:2005-08-20    收藏此頁 
     
     
     三.查詢語句 (SELECT) 部分

      SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……] WHERE 條件;

      字段名可以帶入函數
      例如: COUNT(*), MIN(字段名), MAX(字段名), AVG(字段名), DISTINCT(字段名), TO_CHAR(DATE字段名,'YYYY-MM-DD HH24:MI:SS')

      NVL(EXPR1, EXPR2)函數
      解釋:
      IF EXPR1=NULL
      RETURN EXPR2
      ELSE
      RETURN EXPR1

      DECODE(AA﹐V1﹐R1﹐V2﹐R2....)函數
      解釋:
      IF AA=V1 THEN RETURN R1
      IF AA=V2 THEN RETURN R2
      ..…
      ELSE
      RETURN NULL

      LPAD(char1,n,char2)函數
      解釋:
      字符char1按制定的位數n顯示,不足的位數用char2字符串替換左邊的空位

      字段名之間可以進行算術運算
      例如: (字段名1*字段名1)/3

      查詢語句可以嵌套
      例如: SELECT …… FROM
      (SELECT …… FROM表名1, [表名2, ……] WHERE 條件) WHERE 條件2;

      兩個查詢語句的結果可以做集合操作
      例如: 并集UNION(去掉重復記錄), 并集UNION ALL(不去掉重復記錄), 差集MINUS, 交集INTERSECT

      分組查詢
      SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……] GROUP BY字段名1
      [HAVING 條件] ;

      兩個以上表之間的連接查詢

      SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……] WHERE
      表名1.字段名 = 表名2. 字段名 [ AND ……] ;

      SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……] WHERE
      表名1.字段名 = 表名2. 字段名(+) [ AND ……] ;

      有(+)號的字段位置自動補空值

      查詢結果集的排序操作, 默認的排序是升序ASC, 降序是DESC

      SELECT字段名1, 字段名2, …… FROM 表名1, [表名2, ……]
      ORDER BY字段名1, 字段名2 DESC;

      字符串模糊比較的方法

      INSTR(字段名, ‘字符串’)>0
      字段名 LIKE ‘字符串%’ [‘%字符串%’]

      每個表都有一個隱含的字段ROWID, 它標記著記錄的唯一性.

      四.ORACLE里常用的數據對象 (SCHEMA)

      1.索引 (INDEX)

      CREATE INDEX 索引名ON 表名 ( 字段1, [字段2, ……] );
      ALTER INDEX 索引名 REBUILD;

      一個表的索引最好不要超過三個 (特殊的大表除外), 最好用單字段索引, 結合SQL語句的分析執行情況, 也可以建立多字段的組合索引和基于函數的索引

      ORACLE8.1.7字符串可以索引的最大長度為1578 單字節
      ORACLE8.0.6字符串可以索引的最大長度為758 單字節

      2.視圖 (VIEW)

      CREATE VIEW 視圖名AS SELECT …. FROM …..;
      ALTER VIEW視圖名 COMPILE;

      視圖僅是一個SQL查詢語句, 它可以把表之間復雜的關系簡潔化.

      3.同義詞 (SYNONMY)
      CREATE SYNONYM同義詞名FOR 表名;
      CREATE SYNONYM同義詞名FOR 表名@數據庫鏈接名;

      4.數據庫鏈接 (DATABASE LINK)
      CREATE DATABASE LINK數據庫鏈接名CONNECT TO 用戶名 IDENTIFIED BY 密碼 USING ‘數據庫連接字符串’; 數據庫連接字符串可以用NET8 EASY CONFIG或者直接修改TNSNAMES.ORA里定義.

      數據庫參數global_name=true時要求數據庫鏈接名稱跟遠端數據庫名稱一樣

      數據庫全局名稱可以用以下命令查出
      SELECT * FROM GLOBAL_NAME;

      查詢遠端數據庫里的表
      SELECT …… FROM 表名@數據庫鏈接名;

      五.權限管理 (DCL) 語句

      1.GRANT 賦于權限
      常用的系統權限集合有以下三個:
      CONNECT(基本的連接), RESOURCE(程序開發), DBA(數據庫管理)
      常用的數據對象權限有以下五個:
      ALL ON 數據對象名, SELECT ON 數據對象名, UPDATE ON 數據對象名DELETE ON 數據對象名, INSERT ON 數據對象名, ALTER ON 數據對象名

      GRANT CONNECT, RESOURCE TO 用戶名;
      GRANT SELECT ON 表名 TO 用戶名;
      GRANT SELECT, INSERT, DELETE ON表名 TO 用戶名1, 用戶名2;

      2.REVOKE 回收權限

      REVOKE CONNECT, RESOURCE FROM 用戶名;
      REVOKE SELECT ON 表名 FROM 用戶名;
      REVOKE SELECT, INSERT, DELETE ON表名 FROM 用戶名1, 用戶名2;

    posted @ 2008-04-09 09:59 forgood 閱讀(356) | 評論 (3)編輯 收藏

    Applet包的介紹

            在java中的java.applet包中,包含三個接口和一個類。
            三個接口分別是:
            AppletContext:該接口對應Applet的運行環境,包含Applet的文檔以及和它在同一個文檔中的其他Applet,具體就是裝入Applet的瀏覽器和appliviewer環境。此接口中的方法可以使applet得到關于它環境方面的信息。
            Appletstub:該接口當applet第一次被創建的時候,使用Applet的setStub方法(public final void setStub(AppletStub stub))把applet stub連接到它,此stub充當了Applet和瀏覽器或appletviewer環境之間的接口,應用程序在此環境中運行。
            AudioClip:該接口是用于播放音頻剪輯的簡單抽象。多個AudioClip項能夠同時播放,得到的聲音混合在一起可產生合成聲音。它有三個方法loop、play、stop

               
    Applet是一種不適合單獨運行但可嵌入到其他程序中運行的小應用程序。它的直接父類是java.awt.panel類。

    posted @ 2008-04-03 10:49 forgood 閱讀(288) | 評論 (0)編輯 收藏

    C#學習筆記一

     

    第一章   設計模式概述

    設計模式能夠使解決方案既優雅簡單,又可復用。設計模式僅僅是一些項目之間和程序員之間面向對象代碼的簡便方法,設計模式背后的思想很簡單:對通用的對象間的相互作用方式進行記錄和編目(程序員經常發現這些對象見的相互終于哦用方式很有用)。換言之,設計模式描述了對象如何進行通信才能不牽扯相互的數據模式和方法,保持這種獨立性一直是一個好的面向對象程序設計的目標。從而可以實現代碼的可復用性。

    1.       設計模式

    設計模式是對讀者經常遇到的設計問題的可再現的解決方案。

    設計模式建立了一系列描述如何完成軟件開發領域中特定任務的規則。

    設計模式更關注于復用和重復出現的結構設計方案,而框架注重于具體的設計和實現。

    模式提出了一個發生在特定設計環境中的可重復出現的設計問題,并提供了解決方案

    模式識別并確定類和實例層次上或組件層次上的抽象關系

    設計模式有三種類型

             創建型模式是創建對象而不是直接實例化對象,這會使程序在判斷給定情況下創建那一個對象時更靈活。

             結構型模式可以將一組對象組合成更大的結構,例如復雜的用戶界面和報表數據

             行為型模式定義系統內對象間的通信,以及復雜程序中的流程控制

    2.       關于面向對象方法

          封裝和繼承能讓程序員達到分離類的目的,一個繼承父類的類能訪問父類所有方法和所有非私有變量,但是如果一個功能完整的類開始繼承層次結構,可能過多的限制住了自己,也會給特定的實現帶去累贅,設計模式建議遵循下列原則:針對接口編程,而不是針對實現編程。即在任何類層次結構的頂端,定義的是一個抽象類或一個接口,他沒有實現方法,但是定義了該類需要支持的方法,這樣在所有的派生類中,就會有更大的自由度去實現這些方法,能最大限度地滿足你的要求。

             對象組合,這是一種可以包含其他對象的對象結構,即把幾個對象封裝在另一個對象中,當編寫比較復雜的程序,對象組合具有一些優勢,新的對象擁有一個最適合于要完成的目標的接口,而不是擁有父類中的所有方法,說明了編程的第二個原則:優先使用對象組合,而不是繼承。

            

    C#基礎知識

             C#javavb的區別

             C#Java都是區別大小寫的;C#中的每一條語句都已分號結束;而vb是不區分大小寫的,

             C#中的修飾符const的含義是:被命名的值是一個常數,不能更改。

    數據類型

             基本數據類型的長度與計算機或操作系統的類型無關。

             寬度窄的數據類型可以直接賦給較寬的數據類型,并能自動轉化為新類型。

             可以通過強制轉化把較寬的類型縮減成較窄的類型,這種轉化需要把數據類型的名稱放在圓括號內。

             Javac#的布爾變量只能接受保留字truefalse所表示的值,與cc++不同,不能將數值型數據賦給布爾型變量,也不能在布爾類型和其他數據類型之間轉化。

    數值與字符串間的轉化,可以使用Convert類的方法實現數值轉化成字符串或將字符串轉化成數值。例如:

    String s=Convert.ToString(x);

    Float y=Convert.ToSingle(s);   //single代表一個單精度浮點數

    數值型對象也提供了各種格式話方法類指定小數位數

    Float x=12.3453234f;

    String s=x.ToString(“###.###”); //gives 12.345

    注意最后一位進行四舍五入

    C#java允許在一條語句里聲明同一類型的多個變量

    數值型常量,任何數如果沒有小數部分的話,就自動為整數類型,如果有小數部分 ,就自動為double類型,如果想指定成不同的類型,可以使用各種前綴和后綴字符。

    C#中有三個保留字常量,truefalsenullnull表示一個對象變量還沒有 指定任何對象。

     

    字符常量

    用但引號把字符括起來表示字符常量,轉意字符和cjava中約定的一樣。

     

     

    C#java的區別

    1.       許多系統對象方法都有相同的方法名,只是在大小寫形式上有區別

    2.       C#不提供throws關鍵字,該關鍵字使編譯器檢查你是否鋪貨了一個方法拋出的異常。

    3.       C#對于布局管理器有更多的限制,因為他是以windows系統為中心的,大多數時候采用的圖形元素的絕對位置。

    4.       C#允許運算符重載

    5.       C#引進了代理和索引器

    6.       C#有枚舉類型

    7.       C#有不安全模式,在這種模式下可以使用指針

    8.       必須專門聲明一個方法能被覆蓋及一個方法能覆蓋另一個方法

    9.       不能通過聲明來區別繼承和接口實現,他們的聲明方式是一樣的

    10.   Switch語句允許使用字符串變量,如果變量沒有被匹配,必須有一個默認情況,否則會出現錯誤,break語句是必須的。

    11.   布爾值變量類型在C#中拼為“bool”,而java中拼為“boolean

     

    C#C的區別

    1.       C#通常不能使用指針

    2.       可以在一個方法里的任何位置聲明變量,不必把聲明語句放在方法的頂端

    3.       使用一個對象前,不一定要聲明它,可以在用到的時候在定義

    4.       C#對結構體類型偶那個的定義有些不同,他根本不支持聯合類型

    5.       C#有枚舉類型,允許一系列被命名的量(如顏色或一周里的每一天)賦值為連續的數值,但是語法有些不同。

    6.       C#沒有位域,也就是說,變量至少要占用一個字節的存儲空間

    7.       C#不支持變長參數列表,必須針對參數值和類型定義一個方法,然而C#語句允許函數的最后一個參數為可變參數數組

    8.       C#引入了代理和索引器的思想,這些在其他流行的語言中是沒有的。

     

     

    C#編寫windows程序

    1.       C#中的對象

    C#中的任何食物都被看做是對象,對象包含數據并具有操作數據的方法,

    整型變量、浮點型變量和雙精度型變量也是對象,他們也具有方法

    注意:

               數值類型的轉化是用方法而不是外部函數完成的。在把一個數值格式化成一個特定的字符串時,每種數值類型都提供了一個格式化方法。

    2.       受管語言和垃圾自動收集

    C#VB.NET都是受管語言,有兩個含義:一個是兩者被編譯成中間的底層語言,都使用通用語言運行時(Common Language RuntimeCLR)執行編譯后的代碼,或者進一步編譯這些代碼。另一方面,受管語言都是垃圾自動收集的,垃圾自動收集語言負責師傅拿個不用的內存,垃圾收集系統一旦檢測到變量、數組或對象不在被引用,就把相應的內存空間釋放回系統,在大多數情況下,根本不用考慮內存的分配與釋放問題。

    posted @ 2008-04-01 16:54 forgood 閱讀(280) | 評論 (0)編輯 收藏

    java虛擬機讀取其他進程的數據

        我們在java程序中可以產生其他的應用程序的進程,在java程序中啟動的進程稱為子進程,啟動了進程的java程序稱為父進程。子進程沒有鍵盤和顯示器,子進程的標準輸入和輸出不在連接到鍵盤和顯示器,而是以管道流的形式連接到父進程的一個輸出流和輸入流對象上,調用Process類的getOutputStream和getInputStream方法可以達到這個輸出流和輸入流對象。子進程從標準輸入讀取到的內容是父進程通過輸出流對象寫入管道的數據,子進程寫入標準輸出的數據通過管道傳送到父進程的輸入流對象中,父進程從這個輸入流對象中讀取到的內容就是子進程寫入到標準輸出的數據。

    posted @ 2008-03-21 14:00 forgood 閱讀(339) | 評論 (0)編輯 收藏

    僅列出標題
    共8頁: 上一頁 1 2 3 4 5 6 7 8 下一頁 
    主站蜘蛛池模板: 搡女人免费免费视频观看| 7m凹凸精品分类大全免费| 久久夜色精品国产亚洲| 3d成人免费动漫在线观看| 亚洲AV综合永久无码精品天堂| 国产亚洲精品AA片在线观看不加载| 日本视频在线观看永久免费| 亚洲色大成网站www永久男同| JLZZJLZZ亚洲乱熟无码| 精品福利一区二区三区免费视频| 国产成人精品久久亚洲高清不卡| 国产精品亚洲精品日韩已满| 毛片免费vip会员在线看| 国产亚洲精品免费视频播放| 亚洲欧美日韩一区二区三区在线| 亚洲精品高清无码视频| 美女被免费视频网站a国产| 免费看无码特级毛片| 亚洲中文无码亚洲人成影院| 国产成A人亚洲精V品无码| 国产精品深夜福利免费观看| 99精品视频在线视频免费观看| 视频一区二区三区免费观看| 亚洲精品乱码久久久久久下载 | 免费无码AV片在线观看软件| 一个人免费观看视频在线中文| 亚洲AV一二三区成人影片| 亚洲精品无码mv在线观看网站| 四虎在线免费播放| 久久国产高潮流白浆免费观看| 免费手机在线看片| 亚洲国产日韩综合久久精品| 亚洲av不卡一区二区三区 | 亚洲熟妇丰满xxxxx| 亚洲国语精品自产拍在线观看| www.91亚洲| 性感美女视频在线观看免费精品| 四虎免费影院ww4164h| 久久久久久国产精品免费免费男同| 一级毛片在线完整免费观看| 亚洲精品国产首次亮相|