初識Java內(nèi)部類
              提起Java內(nèi)部類(Inner Class)可能很多人不太熟悉,實(shí)際上類似的概念在C++里也有,那就是嵌套類(Nested Class),關(guān)于這兩者的區(qū)別與聯(lián)系,在下文中會有對比。內(nèi)部類從表面上看,就是在類中又定義了一個類(下文會看到,內(nèi)部類可以在很多地方定義),而實(shí)際上并沒有那么簡單,乍看上去內(nèi)部類似乎有些多余,它的用處對于初學(xué)者來說可能并不是那么顯著,但是隨著對它的深入了解,你會發(fā)現(xiàn)Java的設(shè)計(jì)者在內(nèi)部類身上的確是用心良苦。學(xué)會使用內(nèi)部類,是掌握J(rèn)ava高級編程的一部分,它可以讓你更優(yōu)雅地設(shè)計(jì)你的程序結(jié)構(gòu)。下面從以下幾個方面來介紹:
              ·第一次見面
          public interface Contents {
              int value();
          }
          public interface Destination {
              String readLabel();
          }
          public class Goods {
              private class Content implements Contents {
                  private int i = 11;
                  public int value() {
                      return i;
                  }
              }
              protected class GDestination implements Destination {
                  private String label;
                  private GDestination(String whereTo) {
                      label = whereTo;
                  }
                  public String readLabel() {
                      return label;
                  }
              }
              public Destination dest(String s) {
                  return new GDestination(s);
              }
              public Contents cont() {
                  return new Content();
              }
          }
          class TestGoods {
              public static void main(String[] args) {
                  Goods p = new Goods();
                  Contents c = p.cont();
                  Destination d = p.dest("Beijing");
              }
          }
              在這個例子里類Content和GDestination被定義在了類Goods內(nèi)部,并且分別有著protected和private修飾符來控制訪問級別。Content代表著Goods的內(nèi)容,而GDestination代表著Goods的目的地。它們分別實(shí)現(xiàn)了兩個接口Content和Destination。在后面的main方法里,直接用 Contents c和Destination d進(jìn)行操作,你甚至連這兩個內(nèi)部類的名字都沒有看見!這樣,內(nèi)部類的第一個好處就體現(xiàn)出來了——隱藏你不想讓別人知道的操作,也即封裝性。
              同時,我們也發(fā)現(xiàn)了在外部類作用范圍之外得到內(nèi)部類對象的第一個方法,那就是利用其外部類的方法創(chuàng)建并返回。上例中的cont()和dest()方法就是這么做的。那么還有沒有別的方法呢?當(dāng)然有,其語法格式如下:
              outerObject=new outerClass(Constructor Parameters);
              outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
              注意在創(chuàng)建非靜態(tài)內(nèi)部類對象時,一定要先創(chuàng)建起相應(yīng)的外部類對象。至于原因,也就引出了我們下一個話題——
              ·非靜態(tài)內(nèi)部類對象有著指向其外部類對象的引用
              對剛才的例子稍作修改:
          public class Goods {
              private valueRate=2;
              private class Content implements Contents {
                  private int i = 11*valueRate;
                  public int value() {
                      return i;
                  }
              }
              protected class GDestination implements Destination {
                  private String label;
                  private GDestination(String whereTo) {
                      label = whereTo;
                  }
                  public String readLabel() {
                      return label;
                  }
              }
              public Destination dest(String s) {
                  return new GDestination(s);
              }
              public Contents cont() {
                  return new Content();
              }
          }
              修改的部分用藍(lán)色顯示了。在這里我們給Goods類增加了一個private成員變量valueRate,意義是貨物的價值系數(shù),在內(nèi)部類Content的方法value()計(jì)算價值時把它乘上。我們發(fā)現(xiàn),value()可以訪問valueRate,這也是內(nèi)部類的第二個好處——一個內(nèi)部類對象可以訪問創(chuàng)建它的外部類對象的內(nèi)容,甚至包括私有變量!這是一個非常有用的特性,為我們在設(shè)計(jì)時提供了更多的思路和捷徑。要想實(shí)現(xiàn)這個功能,內(nèi)部類對象就必須有指向外部類對象的引用。Java編譯器在創(chuàng)建內(nèi)部類對象時,隱式的把其外部類對象的引用也傳了進(jìn)去并一直保存著。這樣就使得內(nèi)部類對象始終可以訪問其外部類對象,同時這也是為什么在外部類作用范圍之外向要創(chuàng)建內(nèi)部類對象必須先創(chuàng)建其外部類對象的原因。
              有人會問,如果內(nèi)部類里的一個成員變量與外部類的一個成員變量同名,也即外部類的同名成員變量被屏蔽了,怎么辦?沒事,Java里用如下格式表達(dá)外部類的引用:
          outerClass.this
              有了它,我們就不怕這種屏蔽的情況了。
              ·靜態(tài)內(nèi)部類
              和普通的類一樣,內(nèi)部類也可以有靜態(tài)的。不過和非靜態(tài)內(nèi)部類相比,區(qū)別就在于靜態(tài)內(nèi)部類沒有了指向外部的引用。這實(shí)際上和C++中的嵌套類很相像了,Java內(nèi)部類與C++嵌套類最大的不同就在于是否有指向外部的引用這一點(diǎn)上,當(dāng)然從設(shè)計(jì)的角度以及以它一些細(xì)節(jié)來講還有區(qū)別。
              除此之外,在任何非靜態(tài)內(nèi)部類中,都不能有靜態(tài)數(shù)據(jù),靜態(tài)方法或者又一個靜態(tài)內(nèi)部類(內(nèi)部類的嵌套可以不止一層)。不過靜態(tài)內(nèi)部類中卻可以擁有這一切。這也算是兩者的第二個區(qū)別吧。
              ·局部內(nèi)部類
              是的,Java內(nèi)部類也可以是局部的,它可以定義在一個方法甚至一個代碼塊之內(nèi)。
          public class Goods1 {
               public Destination dest(String s) {
                    class GDestination implements Destination {
                         private String label;
                         private GDestination(String whereTo) {
                              label = whereTo;
                         }
                         public String readLabel() { return label; }
                    }
                    return new GDestination(s);
               }
               public static void main(String[] args) {
                    Goods1 g= new Goods1();
                    Destination d = g.dest("Beijing");
               }
          }
              上面就是這樣一個例子。在方法dest中我們定義了一個內(nèi)部類,最后由這個方法返回這個內(nèi)部類的對象。如果我們在用一個內(nèi)部類的時候僅需要創(chuàng)建它的一個對象并創(chuàng)給外部,就可以這樣做。當(dāng)然,定義在方法中的內(nèi)部類可以使設(shè)計(jì)多樣化,用途絕不僅僅在這一點(diǎn)。
              下面有一個更怪的例子:
          public class Goods2{
               private void internalTracking(boolean b) {
                    if(b) {
                         class TrackingSlip {
                              private String id;
                              TrackingSlip(String s) {
                                   id = s;
                              }
                              String getSlip() { return id; }
                         }
                         TrackingSlip ts = new TrackingSlip("slip");
                         String s = ts.getSlip();
                    }
               }
               public void track() { internalTracking(true); }
               public static void main(String[] args) {
                    Goods2 g= new Goods2();
                    g.track();
               }
          }
              你不能在if之外創(chuàng)建這個內(nèi)部類的對象,因?yàn)檫@已經(jīng)超出了它的作用域。不過在編譯的時候,內(nèi)部類TrackingSlip和其他類一樣同時被編譯,只不過它由它自己的作用域,超出了這個范圍就無效,除此之外它和其他內(nèi)部類并沒有區(qū)別。
              ·匿名內(nèi)部類
              java的匿名內(nèi)部類的語法規(guī)則看上去有些古怪,不過如同匿名數(shù)組一樣,當(dāng)你只需要創(chuàng)建一個類的對象而且用不上它的名字時,使用內(nèi)部類可以使代碼看上去簡潔清楚。它的語法規(guī)則是這樣的:
              new interfacename(){......}; 或 new superclassname(){......};
              下面接著前面繼續(xù)舉例子:
          public class Goods3 {
               public Contents cont(){
                    return new Contents(){
                         private int i = 11;
                         public int value() {
                              return i;
                         }
                    };
               }
          }
              這里方法cont()使用匿名內(nèi)部類直接返回了一個實(shí)現(xiàn)了接口Contents的類的對象,看上去的確十分簡潔。
              在java的事件處理的匿名適配器中,匿名內(nèi)部類被大量的使用。例如在想關(guān)閉窗口時加上這樣一句代碼:
          frame.addWindowListener(new WindowAdapter(){
               public void windowClosing(WindowEvent e){
                    System.exit(0);
               }
          });
              有一點(diǎn)需要注意的是,匿名內(nèi)部類由于沒有名字,所以它沒有構(gòu)造函數(shù)(但是如果這個匿名內(nèi)部類繼承了一個只含有帶參數(shù)構(gòu)造函數(shù)的父類,創(chuàng)建它的時候必須帶上這些參數(shù),并在實(shí)現(xiàn)的過程中使用super關(guān)鍵字調(diào)用相應(yīng)的內(nèi)容)。如果你想要初始化它的成員變量,有下面幾種方法:
              1.如果是在一個方法的匿名內(nèi)部類,可以利用這個方法傳進(jìn)你想要的參數(shù),不過記住,這些參數(shù)必須被聲明為final。
              2.將匿名內(nèi)部類改造成有名字的局部內(nèi)部類,這樣它就可以擁有構(gòu)造函數(shù)了。
              3.在這個匿名內(nèi)部類中使用初始化代碼塊。
              ·為什么需要內(nèi)部類?
              java內(nèi)部類有什么好處?為什么需要內(nèi)部類?
              首先舉一個簡單的例子,如果你想實(shí)現(xiàn)一個接口,但是這個接口中的一個方法和你構(gòu)想的這個類中的一個方法的名稱,參數(shù)相同,你應(yīng)該怎么辦?這時候,你可以建一個內(nèi)部類實(shí)現(xiàn)這個接口。由于內(nèi)部類對外部類的所有內(nèi)容都是可訪問的,所以這樣做可以完成所有你直接實(shí)現(xiàn)這個接口的功能。
              不過你可能要質(zhì)疑,更改一下方法的不就行了嗎?
              的確,以此作為設(shè)計(jì)內(nèi)部類的理由,實(shí)在沒有說服力。
              真正的原因是這樣的,java中的內(nèi)部類和接口加在一起,可以的解決常被C++程序員抱怨java中存在的一個問題——沒有多繼承。實(shí)際上,C++的多繼承設(shè)計(jì)起來很復(fù)雜,而java通過內(nèi)部類加上接口,可以很好的實(shí)現(xiàn)多繼承的效果。

          posted @ 2006-03-02 20:54 killvin| 編輯 收藏

          引言
          在使用response的過程中經(jīng)常會遇到跳轉(zhuǎn)頁面的事情,這個時候有兩種情況供你選擇
          1。就是調(diào)用
          ServletContext.getRequestDispatcher(java.lang.String).forward(request ,
          response) ;
          2。就是調(diào)用response.setRedirect(),可是這兩個方法有什么不同呢?


          看看TSS上關(guān)于這個問題的解釋:
          Difference request.forward() and response.sendRedirect .
          Posted by: Kapil Israni on August 24, 2000 in response to Message #2253 1
          replies in this thread
          i suppose u r talking bout requestDispatcher.forward() here.

          well basically both method calls redirect u to new resource/page/servlet.

          the difference between the two is that sendRedirect always sends a header
          back to the client/browser. this header then contains the
          resource(page/servlet) which u wanted to be redirected. the browser uses
          this header to make another fresh request. thus sendRedirect has a overhead
          as to the extra remort trip being incurred. its like any other Http request
          being generated by ur browser. the advantage is that u can point to any
          resource(whether on the same domain or some other domain). for eg if
          sendRedirect was called at www.mydomain.com then it can also be used to
          redirect a call to a resource on www.theserverside.com.

          where as in case of forward() call, the above is not true. resources from
          the server, where the fwd. call was made, can only be requested for. but
          the major diff between the two is that forward just routes the request to
          the new resources which u specify in ur forward call. that means this route
          is made by the servlet engine at the server level only. no headers r sent
          to the browser which makes this very eficient. also the request and
          response objects remain the same both from where the forward call was made
          and the resource which was called.

          i hope i have hit ur question right.

          posted @ 2006-03-02 20:54 killvin| 編輯 收藏

          Java Language Keywords

          Here's a list of keywords in the Java language. These words are reserved — you cannot use any of these words as names in your programs. true, false, and null are not keywords but they are reserved words, so you cannot use them as names in your programs either.

          abstract    |   continue    |   for    |    new     |   switch
          assert***  |   default     |   goto*     |   package     |   synchronized
          boolean    |   do     |   if     |   private     |   this
          break         |   double     |   implements    |   protected    |   throw
          byte            |   else     |   import     |   public  throws
          case          |   enum****    |   instanceof    |   return     |   transient 
          catch         |   extends     |   int     |   short     |   try
          char           |   final     |   interface    |   static     |   void
          class         |   finally     |   long     |   strictfp**    |   volatile
          const*       |   float     |   native     |   super     |   while


          *   not used
          **   added in 1.2
          ***   added in 1.4 
          ****   added in 5.0                                    

           

          Key: strictfp**

          使用對象:類、方法

          自Java2以來,Java語言增加了一個關(guān)鍵字strictfp,雖然這個關(guān)鍵字在大多數(shù)場合比較少用,但是還是有必要了解一下。

          strictfp的意思是FP-strict,也就是說精確浮點(diǎn)的意思。在Java虛擬機(jī)進(jìn)行浮點(diǎn)運(yùn)算時,如果沒有指定strictfp關(guān)鍵字時,Java的編譯器以及運(yùn)行環(huán)境在對浮點(diǎn)運(yùn)算的表達(dá)式是采取一種近似于我行我素的行為來完成這些操作,以致于得到的結(jié)果往往無法令你滿意。而一旦使用了strictfp來聲明一個類、接口或者方法時,那么所聲明的范圍內(nèi)Java的編譯器以及運(yùn)行環(huán)境會完全依照浮點(diǎn)規(guī)范IEEE-754來執(zhí)行。因此如果你想讓你的浮點(diǎn)運(yùn)算更加精確,而且不會因?yàn)椴煌挠布脚_所執(zhí)行的結(jié)果不一致的話,那就請用關(guān)鍵字strictfp。

          你可以將一個類、接口以及方法聲明為strictfp,但是不允許對接口中的方法以及構(gòu)造函數(shù)聲明strictfp關(guān)鍵字,例如下面的代碼:

          1. 合法的使用關(guān)鍵字strictfp

          strictfp interface A {}

          public strictfp class FpDemo1 {
              strictfp void f() {}
          }

          2. 錯誤的使用方法

          interface A {
              strictfp void f();
          }

          public class FpDemo2 {
              strictfp FpDemo2() {}
          }

          一旦使用了關(guān)鍵字strictfp來聲明某個類、接口或者方法時,那么在這個關(guān)鍵字所聲明的范圍內(nèi)所有浮點(diǎn)運(yùn)算都是精確的,符合IEEE-754規(guī)范的。例如一個類被聲明為strictfp,那么該類中所有的方法都是strictfp的。

           

          Keys: volatile

          使用對象:字段

          介紹:因?yàn)楫惒骄€程可以訪問字段,所以有些優(yōu)化操作是一定不能作用在字段上的。volatile有時

          可以代替synchronized。

           

          Keys:transient

            使用對象:字段

            介紹:字段不是對象持久狀態(tài)的一部分,不應(yīng)該把字段和對象一起串起。

          posted @ 2006-03-02 20:53 killvin| 編輯 收藏

          引言

           記得當(dāng)初參與某公司的ERP項(xiàng)目中,接觸過異常框架這個概念,可是似乎并沒有感覺到當(dāng)時技術(shù)經(jīng)理提出這個概念的意義,而且他也對這個概念似乎很"保守",雖然按照他的思路去執(zhí)行,但沒有理解的概念再實(shí)施起來的時候總是覺得很"別扭",而如今面對自己要設(shè)計(jì)咚咚了,不得不重新審視異常這個概念,JAVA異常的介紹文章在網(wǎng)絡(luò)上非常的少,而對于如何構(gòu)件J2EE的異常處理框架更顯的稀少,于是就促使自己寫下了這樣的文章。

           本文只是自己的一些愚見,希望和大家相互學(xué)習(xí)。Email:Killvin@hotmail.com

          概念

          什么是異常?

          異常(exception)應(yīng)該是異常事件(exceptional event)的縮寫。
          異常定義:異常是一個在程序執(zhí)行期間發(fā)生的事件,它中斷正在執(zhí)行的程序的正常的指令流。
          當(dāng)在一個方法中發(fā)生錯誤的時候,這個方法創(chuàng)建一個對象,并且把它傳遞給運(yùn)行時系統(tǒng)。這個對象被叫做異常對象,它包含了有關(guān)錯誤的信息,這些信息包括錯誤的類型和在程序發(fā)生錯誤時的狀態(tài)。創(chuàng)建一個錯誤對象并把它傳遞給運(yùn)行時系統(tǒng)被叫做拋出異常。
          一個方法拋出異常后,運(yùn)行時系統(tǒng)就會試著查找一些方法來處理它。這些處理異常的可能的方法的集合是被整理在一起的方法列表,這些方法能夠被發(fā)生錯誤的方法調(diào)用。這個方法列表被叫做堆棧調(diào)用(call stack)

          運(yùn)行時系統(tǒng)搜尋包含能夠處理異常的代碼塊的方法所請求的堆棧。這個代碼塊叫做異常處理器,搜尋首先從發(fā)生的方法開始,然后依次按著調(diào)用方法的倒序檢索調(diào)用堆棧。當(dāng)找到一個相應(yīng)的處理器時,運(yùn)行時系統(tǒng)就把異常傳遞給這個處理器。一個異常處理器要適當(dāng)?shù)乜紴V拋出的異常對象的類型和異常處理器所處理的異常的類型是否匹配。異常被捕獲以后,異常處理器關(guān)閉。如果運(yùn)行時系統(tǒng)搜尋了這個方法的所有的調(diào)用堆棧,而沒有找到相應(yīng)的異常處理器。

           

          怎么設(shè)計(jì)異常框架

          任何的異常都是Throwable類(為何不是接口??),并且在它之下包含兩個字類Error / Exception,而Error僅在當(dāng)在Java虛擬機(jī)中發(fā)生動態(tài)連接失敗或其它的定位失敗的時候,Java虛擬機(jī)拋出一個Error對象。典型的簡易程序不捕獲或拋出Errors對象,你可能永遠(yuǎn)不會遇到需要實(shí)例化Error的應(yīng)用,那就讓我們關(guān)心一下Exception

          Exception中比較重要的就是RuntimeException-運(yùn)行時異常(當(dāng)然這個名字是存在爭議的,因?yàn)槿魏蔚漠惓6贾粫l(fā)生在運(yùn)行時),為什么說這個類時很重要的呢?因?yàn)樗苯雨P(guān)系到你的異常框架的設(shè)計(jì),仔細(xì)看RuntimeException

          A method is not required to declare in its throws clause any subclasses of RuntimeException that might be thrown during the execution of the method but not caught.

          -可能在執(zhí)行方法期間拋出但未被捕獲的 RuntimeException 的任何子類都無需在 throws 子句中進(jìn)行聲明。

          也就是說你的應(yīng)用應(yīng)該不去“關(guān)心”(說不關(guān)心是不服責(zé)任的,但只是你不應(yīng)該試圖實(shí)例化它的字類)RuntimeException,就如同你不應(yīng)該關(guān)心Error的產(chǎn)生與處理一樣!RuntimeException描述的是程序的錯誤引起來的,因該由程序負(fù)擔(dān)這個責(zé)任!(<B>從責(zé)任這個角度看Error屬于JVM需要負(fù)擔(dān)的責(zé)任;RuntimeException是程序應(yīng)該負(fù)擔(dān)的責(zé)任;checked exception 是具體應(yīng)用負(fù)擔(dān)的責(zé)任</B>)

          那就有人會問,那我該關(guān)心什么!答案就是除了Error與RuntimeException,其他剩下的異常都是你需要關(guān)心的,而這些異常類統(tǒng)稱為Checked Exception,至于Error與RuntimeException則被統(tǒng)稱為Unchecked Exception.


          異常的概念就這些了,即使你在網(wǎng)絡(luò)上搜索也就不過如此,是不是感覺到有點(diǎn)清晰又有點(diǎn)模糊?那么怎么該如何在這樣單薄而模糊的概念下設(shè)計(jì)J2EE的異常框架呢?


          解決方案:J2EE異常框架

          我們拿一個模擬的例子來說明異常框架的設(shè)計(jì)過程,比如我們要對外提供doBusiness()這個業(yè)務(wù)方法

          public void doBusiness() throws xxxBusinessException

          當(dāng)客戶端調(diào)用這樣的方法的時候應(yīng)該這樣處理異常(包括處理RuntimeException , checked exception)
          <B>記住,無論如何我們都不希望或者確切的說是不應(yīng)該將RuntimeException這樣的異常暴露給客戶的,因?yàn)樗麄儧]有解決這個問題的責(zé)任!</B>
          我們暫時將Struts中的某個Action看作時客戶端,其中doExecute(....)要調(diào)用doBusiness()這個方法

          public void doAction(......)
          {
           try
           {

            xxx.doBusiness();
           }
           catch(Exception e)
           {
             if(e instanceof RuntimeException) 
             {
              // catch runtime exception
              // 你可以在這里將捕獲到的RuntimeException
              // 將異常通知給某個負(fù)責(zé)此程序的程序員,讓他知道他
              // 自己犯了多么低級的錯誤!


             }else
             {
              //checked exception such as xxxBusinessException
              //將這樣的異常暴露給客戶顯示    

             }

           }
          }

          我們可以這樣設(shè)計(jì)xxxBusinessException

          public class xxxBusinessException extends ApplicationException
          {
              public xxxBusinessException(String s){
                  super(s);

          };

          import java.io.PrintStream;
          import java.io.PrintWriter;
          public class ApplicationException extends Exception {
                 /** A wrapped Throwable */
                 protected Throwable cause;
                 public ApplicationException() {
                     super("Error occurred in application.");
                 }
                 public ApplicationException(String message)  {
                     super(message);
                 }
                 public ApplicationException(String message, Throwable cause)  {
                     super(message);
                     this.cause = cause;
                 }
                 // Created to match the JDK 1.4 Throwable method.
                 public Throwable initCause(Throwable cause)  {
                     this.cause = cause;
                     return cause;
                 }
                 public String getMessage() {
                     // Get this exception's message.
                     String msg = super.getMessage();
                     Throwable parent = this;
                     Throwable child;
                     // Look for nested exceptions.
                     while((child = getNestedException(parent)) != null) {
                         // Get the child's message.
                         String msg2 = child.getMessage();
                         // If we found a message for the child exception,
                         // we append it.
                         if (msg2 != null) {
                             if (msg != null) {
                                 msg += ": " + msg2;
                             } else {
                                 msg = msg2;
                             }
                         }
                         // Any nested ApplicationException will append its own
                         // children, so we need to break out of here.
                         if (child instanceof ApplicationException) {
                             break;
                         }
                         parent = child;
                     }
                     // Return the completed message.
                     return msg;
                 }
                 public void printStackTrace() {
                     // Print the stack trace for this exception.
                     super.printStackTrace();
                     Throwable parent = this;
                     Throwable child;
                     // Print the stack trace for each nested exception.
                     while((child = getNestedException(parent)) != null) {
                         if (child != null) {
                             System.err.print("Caused by: ");
                             child.printStackTrace();
                             if (child instanceof ApplicationException) {
                                 break;
                             }
                             parent = child;
                         }
                     }
                 }
                 public void printStackTrace(PrintStream s) {
                     // Print the stack trace for this exception.
                     super.printStackTrace(s);
                     Throwable parent = this;
                     Throwable child;
                     // Print the stack trace for each nested exception.
                     while((child = getNestedException(parent)) != null) {
                         if (child != null) {
                             s.print("Caused by: ");
                             child.printStackTrace(s);
                             if (child instanceof ApplicationException) {
                                 break;
                             }
                             parent = child;
                         }
                     }
                 }
                 public void printStackTrace(PrintWriter w) {
                     // Print the stack trace for this exception.
                     super.printStackTrace(w);
                     Throwable parent = this;
                     Throwable child;
                     // Print the stack trace for each nested exception.
                     while((child = getNestedException(parent)) != null) {
                         if (child != null) {
                             w.print("Caused by: ");
                             child.printStackTrace(w);
                             if (child instanceof ApplicationException) {
                                 break;
                             }
                             parent = child;
                         }
                     }
                 }
                 public Throwable getCause()  {
                     return cause;
                 }
          }

          而"聰明"的讀者肯定要問我那doBusiness()這個業(yè)務(wù)方法該如何包裝異常呢?

           public void doBusiness() throw xxxBusinessException
           {
             try
             {
               execute1(); // if it throw exception1

               exexute2(); // if it throw exception 2

               .... .....

             }
             catch (exception1 e1)
             {
              throw new xxxBusinessException(e1);
             }
             catch(exception2 e2)
             {
              throw new xxxBusinessException(e2);
             }
             ........
           }

           也可以這樣

           public void doBusiness() throw xxxBusinessException
           {
             try
             {
               execute1(); // if it throw exception1

               exexute2(); // if it throw exception 2

               .... .....

             }
             catch (Exception e)
             {
              // 注意很多應(yīng)用在這里根本不判斷異常的類型而一股腦的采用
              // throw new xxxBusinessException(e);
              // 而這樣帶來的問題就是xxxBusinessException"吞掉了"RuntimeException
              // 從而將checked excption 與unchecked exception混在了一起!

              // 其實(shí)xxxBusinessException屬于checked excpetion ,它根本不應(yīng)該也不能夠理睬RuntimeException
              if(! e instanceof RuntimeException) throw new xxxBusinessException(e);
             }
           }


          總結(jié)
           1。JAVA的異常分為兩類: checked exception & unchecked excpetion
           2。應(yīng)用開發(fā)中產(chǎn)生的異常都應(yīng)該集成自Exception 但都屬于checked excpetion類型
           3。應(yīng)用中的每一層在包裝并傳遞異常的時候要過濾掉RuntimeException!
           4。從責(zé)任這個角度看Error屬于JVM需要負(fù)擔(dān)的責(zé)任;RuntimeException是程序應(yīng)該負(fù)擔(dān)的責(zé)任;checked exception 是具體應(yīng)用負(fù)擔(dān)的責(zé)任
           5。無論如何我們都不希望或者確切的說是不應(yīng)該將RuntimeException這樣的異常暴露給客戶的,因?yàn)樗麄儧]有解決這個問題的責(zé)任!

          posted @ 2006-03-02 20:50 killvin| 編輯 收藏

          Nasted Class 的介紹,請?jiān)斠妳⒖?/P>

          今天討論的不是不是內(nèi)部類的概念,而是具體使用的一個場景-如何在內(nèi)部類中返回外部對象

          看一段代碼

          import java.util.LinkedList;
          import java.util.List;


          public class OuterClass
          {

           private List listeners = new LinkedList();

           public void addListeners(IListener listener)
           {
            this.listeners.add(listener);
           }


           private OuterClass outer = this;  (1)
           private class InnterClass
           {
            public void publish()
            {
             //將事件發(fā)布出去 (2)
             for(int i=0;i < listeners.size();i++)
             {
              IListener listener = (IListener) listeners.get(i);
              listener.receiveEvent(outer);
             }

            }
           }


           public void execute()
           {
            InnterClass in = new InnterClass(); (3)
            in.publish();

           }
          }

          public interface IListener
          {

          public void receiveEvent(OuterClass obj);
          }

          你可能覺得這個例子很別扭,在哪里讓你覺得難受呢?其實(shí)問題的關(guān)鍵就在于接口IListener的定義,這里需要給receiveEvent方法傳遞的參數(shù)是外部對象!(別激動,下面我會說明需要傳遞的一個場景)

          場景

          在一個GUI系統(tǒng)中,我們要在畫板WorkSpace(WorkSpace實(shí)現(xiàn)了IListener接口)上產(chǎn)生一顆樹,但樹中的每個節(jié)點(diǎn)的產(chǎn)生(繪圖)是我們不知道的算法,系統(tǒng)只為我們提供了一些繪圖的接口,并返回元素的句柄!看來我們需要"包裝"一下這個繪圖的句柄Brush(其實(shí)我把它叫做筆刷,因?yàn)樗恢廊绾?刷"出圖像來,就這點(diǎn)本事!)并對外提供節(jié)點(diǎn)Node這樣一個通用的類。

          此時Node與Brush的關(guān)系就很微妙了,不過我們可以拋開這些外表,看到Node與Brush其實(shí)就是外部類與內(nèi)部類的關(guān)系!-第一步完成了:確定了兩者的關(guān)系

          然而,事情沒有這么簡單,Node類必須處理一些事件,而這些事件理所當(dāng)然只有Brush能夠看懂,而Node根本不知道這樣的事件處理過程,現(xiàn)在有兩個辦法:辦法一,讓Node實(shí)現(xiàn)Brush所有的事件;辦法二,把Brush返回回去,讓它來處理自己的事件,看來辦法二是個好主意,因?yàn)槲铱梢圆魂P(guān)心事件的種類!-第二步完成了:確定了事件處理的責(zé)任

          還沒完呢,你肯定不希望畫板WorkSpace面對的是繪圖的句柄Brush這樣的對象,相反你只希望WokSpace只知道Node的存在!IListener接口中receiveEvent方法的參數(shù)定義為OuterClass 就由此而來!-第三步完成:接口的定義

          public interface IListener
          {

          public void receiveEvent(OuterClass obj);
          }

           既然說清楚了這個問題(應(yīng)該比較清楚了吧?)那改如何實(shí)現(xiàn)這樣一個蹩腳而有無可奈何的設(shè)計(jì)呢?讓我們回憶一下內(nèi)部類,內(nèi)部類擁有訪問外部類的方法與屬性的權(quán)限

           private OuterClass outer = this;  - 這個對外部類的引用就是為內(nèi)部類的訪問準(zhǔn)備的

           private class InnterClass
           {
            public void publish()
            {
             //將事件發(fā)布出去 

             for(int i=0;i < listeners.size();i++)
             {
              IListener listener = (IListener) listeners.get(i);
              listener.receiveEvent(outer);  - 這里不可以返回this,因?yàn)閠his代表的是內(nèi)部類自己
             }
            }

           

           

          參考

          Java Nested class   http://blog.csdn.net/Killvin/archive/2006/01/10/574983.aspx

          初識Java內(nèi)部類    http://blog.csdn.net/killvin/archive/2006/01/10/574991.aspx

          posted @ 2006-03-02 20:49 killvin| 編輯 收藏

          當(dāng)你顯式的使用session.save()或者session.update()操作一個對象的時候,實(shí)際上是用不到unsaved-value的。某些情況下(父子表關(guān)聯(lián)保存),當(dāng)你在程序中并沒有顯式的使用save或者update一個持久對象,那么Hibernate需要判斷被操作的對象究竟是一個已經(jīng)持久化過的持久對象,是一個尚未被持久化過的內(nèi)存臨時對象。例如:

          java代碼: 

            Session session = ...;
            Transaction tx = ...;
            
            Parent parent = (Parent) session.load(Parent.class, id);
            
            Child child = new Child();
            child.setParent(parent);
            child.setName("sun");
            
           10 parent.addChild(child);
           11 s.update(parent);
           12 
           13 s.flush();
           14 tx.commit();
           15 s.close();



          在上例中,程序并沒有顯式的session.save(child); 那么Hibernate需要知道child究竟是一個臨時對象,還是已經(jīng)在數(shù)據(jù)庫中有的持久對象。如果child是一個新創(chuàng)建的臨時對象(本例中就是這種情況),那么Hibernate應(yīng)該自動產(chǎn)生session.save(child)這樣的操作,如果child是已經(jīng)在數(shù)據(jù)庫中有的持久對象,那么Hibernate應(yīng)該自動產(chǎn)生session.update(child)這樣的操作。

          因此我們需要暗示一下Hibernate,究竟child對象應(yīng)該對它自動save還是update。在上例中,顯然我們應(yīng)該暗示Hibernate對child自動save,而不是自動update。那么Hibernate如何判斷究竟對child是save還是update呢?它會取一下child的主鍵屬性 child.getId() ,這里假設(shè)id是 java.lang.Integer類型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等,那么Hibernate認(rèn)為child是新的內(nèi)存臨時對象,發(fā)送save,如果不相等,那么Hibernate認(rèn)為child是已經(jīng)持久過的對象,發(fā)送update。

          unsaved-value="null" (默認(rèn)情況,適用于大多數(shù)對象類型主鍵 Integer/Long/String/...)

          當(dāng)Hibernate取一下child的Id,取出來的是null(在上例中肯定取出來的是null),和unsaved-value設(shè)定值相等,發(fā)送save(child)

          當(dāng)Hibernate取一下child的id,取出來的不是null,那么和unsaved-value設(shè)定值不相等,發(fā)送update(child)

          例如下面的情況:

          java代碼: 

            Session session = ...;
            Transaction tx = ...;
            
            Parent parent = (Parent) session.load(Parent.class, id);
            Child child = (Child) session.load(Child.class, childId);
            
            child.setParent(parent);
            child.setName("sun");
            
           10 parent.addChild(child);
           11 s.update(parent);
           12 
           13 s.flush();
           14 tx.commit();
           15 s.close();



          child已經(jīng)在數(shù)據(jù)庫中有了,是一個持久化的對象,不是新創(chuàng)建的,因此我們希望Hibernate發(fā)送update(child),在該例中,Hibernate取一下child.getId(),和unsave-value指定的null比對一下,發(fā)現(xiàn)不相等,那么發(fā)送update(child)。

          BTW: parent對象不需要操心,因?yàn)槌绦蝻@式的對parent有l(wèi)oad操作和update的操作,不需要Hibernate自己來判斷究竟是save還是update了。我們要注意的只是child對象的操作。另外unsaved-value是定義在Child類的主鍵屬性中的。

          java代碼: 

           1 <class name="Child" table="child">
           2 <id column="id" name="id" type="integer" unsaved-value="null">
           3   <generator class="identity"/>
           4 </id>
           5 ...
           6 </class>



          如果主鍵屬性不是對象型,而是基本類型,如int/long/double/...,那么你需要指定一個數(shù)值型的unsaved-value,例如:

          java代碼: 

           1 unsaved-null="0"



          在此提醒大家,很多人以為對主鍵屬性定義為int/long,比定義為Integer/Long運(yùn)行效率來得高,認(rèn)為基本類型不需要進(jìn)行對象的封裝和解構(gòu)操作,因此喜歡把主鍵定義為int/long的。但實(shí)際上,Hibernate內(nèi)部總是把主鍵轉(zhuǎn)換為對象型進(jìn)行操作的,就算你定義為int/long型的,Hibernate內(nèi)部也要進(jìn)行一次對象構(gòu)造操作,返回給你的時候,還要進(jìn)行解構(gòu)操作,效率可能反而低也說不定。因此大家一定要扭轉(zhuǎn)一個觀點(diǎn),在Hibernate中,主鍵屬性定義為基本類型,并不能夠比定義為對象型效率來的高,而且也多了很多麻煩,因此建議大家使用對象型的Integer/Long定義主鍵。

          unsaved-value="none"和
          unsaved-value="any"

          主主要用在主鍵屬性不是通過Hibernate生成,而是程序自己setId()的時候。

          在這里多說一句,強(qiáng)烈建議使用Hibernate的id generator,或者你可以自己擴(kuò)展Hibernate的id generator,特別注意不要使用有實(shí)際含義的字段當(dāng)做主鍵來用!例如用戶類User,很多人喜歡用用戶登陸名稱做為主鍵,這是一個很不好的習(xí)慣,當(dāng)用戶類和其他實(shí)體類有關(guān)聯(lián)關(guān)系的時候,萬一你需要修改用戶登陸名稱,一改就需要改好幾張表中的數(shù)據(jù)。偶合性太高,而如果你使用無業(yè)務(wù)意義的id generator,那么修改用戶名稱,就只修改user表就行了。

          由這個問題引申出來,如果你嚴(yán)格按照這個原則來設(shè)計(jì)數(shù)據(jù)庫,那么你基本上是用不到手工來setId()的,你用Hibernate的id generator就OK了。因此你也不需要了解當(dāng)

          unsaved-value="none"和
          unsaved-value="any"

          究竟有什么含義了。如果你非要用assigned不可,那么繼續(xù)解釋一下:

          unsaved-value="none" 的時候,由于不論主鍵屬性為任何值,都不可能為none,因此Hibernate總是對child對象發(fā)送update(child)

          unsaved-value="any" 的時候,由于不論主鍵屬性為任何值,都肯定為any,因此Hibernate總是對child對象發(fā)送save(child)

          大多數(shù)情況下,你可以避免使用assigned,只有當(dāng)你使用復(fù)合主鍵的時候不得不手工setId(),這時候需要你自己考慮究竟怎么設(shè)置unsaved-value了,根據(jù)你自己的需要來定。

          BTW: Gavin King強(qiáng)烈不建議使用composite-id,強(qiáng)烈建議使用UserType。

          因此,如果你在系統(tǒng)設(shè)計(jì)的時候,遵循如下原則:

          1、使用Hibernate的id generator來生成無業(yè)務(wù)意義的主鍵,不使用有業(yè)務(wù)含義的字段做主鍵,不使用assigned。

          2、使用對象類型(String/Integer/Long/...)來做主鍵,而不使用基礎(chǔ)類型(int/long/...)做主鍵

          3、不使用composite-id來處理復(fù)合主鍵的情況,而使用UserType來處理該種情況。


          那么你永遠(yuǎn)用的是unsaved-value="null" ,不可能用到any/none/..了。

          posted @ 2006-03-02 20:45 killvin| 編輯 收藏

          先來點(diǎn)概念:

          在Hibernate中,最核心的概念就是對PO的狀態(tài)管理。一個PO有三種狀態(tài):

          1、未被持久化的VO
          此時就是一個內(nèi)存對象VO,由JVM管理生命周期

          2、已被持久化的PO,并且在Session生命周期內(nèi)
          此時映射數(shù)據(jù)庫數(shù)據(jù),由數(shù)據(jù)庫管理生命周期

          3、曾被持久化過,但現(xiàn)在和Session已經(jīng)detached了,以VO的身份在運(yùn)行
          這種和Session已經(jīng)detached的PO還能夠進(jìn)入另一個Session,繼續(xù)進(jìn)行PO狀態(tài)管理,此時它就成為PO的第二種狀態(tài)了。這種PO實(shí)際上是跨了Session進(jìn)行了狀態(tài)維護(hù)的。

          在傳統(tǒng)的JDO1.x中,PO只有前面兩種狀態(tài),一個PO一旦脫離PM,就喪失了狀態(tài)了,不再和數(shù)據(jù)庫數(shù)據(jù)關(guān)聯(lián),成為一個純粹的內(nèi)存VO,它即使進(jìn)入一個新的PM,也不能恢復(fù)它的狀態(tài)了。

          Hibernate強(qiáng)的地方就在于,一個PO脫離Session之后,還能保持狀態(tài),再進(jìn)入一個新的Session之后,就恢復(fù)狀態(tài)管理的能力,但此時狀態(tài)管理需要使用session.update或者session.saveOrUpdate,這就是Hibernate Reference中提到的“requires a slightly different programming model ”

          現(xiàn)在正式進(jìn)入本話題:

          簡單的來說,update和saveOrUpdate是用來對跨Session的PO進(jìn)行狀態(tài)管理的。

          假設(shè)你的PO不需要跨Session的話,那么就不需要用到,例如你打開一個Session,對PO進(jìn)行操作,然后關(guān)閉,之后這個PO你也不會再用到了,那么就不需要用update。

          因此,我們來看看上例:
          java代碼: 

           1 Foo foo=sess.load(Foo.class,id);
           2 foo.setXXX(xxx);
           3 sess.flush();
           4 sess.commit();



          PO對象foo的操作都在一個Session生命周期內(nèi)完成,因此不需要顯式的進(jìn)行sess.update(foo)這樣的操作。Hibernate會自動監(jiān)測到foo對象已經(jīng)被修改過,因此就向數(shù)據(jù)庫發(fā)送一個update的sql。當(dāng)然如果你非要加上sess.update(foo)也不會錯,只不過這樣做沒有任何必要。

          而跨Session的意思就是說這個PO對象在Session關(guān)閉之后,你還把它當(dāng)做一個VO來用,后來你在Session外面又修改了它的屬性,然后你又想打開一個Session,把VO的屬性修改保存到數(shù)據(jù)庫里面,那么你就需要用update了。

          java代碼: 

            // in the first session
            Cat cat = (Cat) firstSession.load(Cat.class, catId);
            Cat potentialMate = new Cat();
            firstSession.save(potentialMate);
            
            // in a higher tier of the application
            cat.setMate(potentialMate);
            
            // later, in a new session
           10 secondSession.update(cat)// update cat
           11 secondSession.update(mate); // update mate
           12 



          cat和mate對象是在第一個session中取得的,在第一個session關(guān)閉之后,他們就成了PO的第三種狀態(tài),和Session已經(jīng)detached的PO,此時他們的狀態(tài)信息仍然被保留下來了。當(dāng)他們進(jìn)入第二個session之后,立刻就可以進(jìn)行狀態(tài)的更新。但是由于對cat的修改操作:cat.setMate(potentialMate); 是在Session外面進(jìn)行的,Hibernate不可能知道cat對象已經(jīng)被改過了,第二個Session并不知道這種修改,因此一定要顯式的調(diào)用secondSession.update(cat); 通知Hibernate,cat對象已經(jīng)修改了,你必須發(fā)送update的sql了。

          所以update的作用就在于此,它只會被用于當(dāng)一個PO對象跨Session進(jìn)行狀態(tài)同步的時候才需要寫。而一個PO對象當(dāng)它不需要跨Session進(jìn)行狀態(tài)管理的時候,是不需要寫update的。

          再談?wù)?SPAN style="COLOR: #ffa34f">saveOrUpdate
          的用場:

          saveOrUpdate和update的區(qū)別就在于在跨Session的PO狀態(tài)管理中,Hibernate對PO采取何種策略。

          例如當(dāng)你寫一個DAOImpl的時候,讓cat對象增加一個mate,如下定義:
          java代碼: 

          1 public void addMate(Cat cat, Mate mate) {
           2     Session session = ...;
           3     Transacton tx = ...;
           4     session.update(cat);
           5     cat.addMate(mate);
           6     tx.commit();
           7     session.close();
           8 };



          顯然你是需要把Hibernate的操作封裝在DAO里面的,讓業(yè)務(wù)層的程序員和Web層的程序員不需要了解Hibernate,直接對DAO進(jìn)行調(diào)用。

          此時問題就來了:上面的代碼運(yùn)行正確有一個必要的前提,那就是方法調(diào)用參數(shù)cat對象必須是一個已經(jīng)被持久化過的PO,也就是來說,它應(yīng)該首先從數(shù)據(jù)庫查詢出來,然后才能這樣用。但是業(yè)務(wù)層的程序員顯然不知道這種內(nèi)部的玄妙,如果他的業(yè)務(wù)是現(xiàn)在增加一個cat,然后再增加它的mate,他顯然會這樣調(diào)用,new一個cat對象出來,然后就addMate:

          java代碼: 

           1 Cat cat = new Cat();
           2 cat.setXXX();
           3 daoimpl.addMate(cat,mate);



          但是請注意看,這個cat對象只是一個VO,它沒有被持久化過,它還不是PO,它沒有資格調(diào)用addMate方法,因此調(diào)用addMate方法不會真正往數(shù)據(jù)庫里面發(fā)送update的sql,這個cat對象必須先被save到數(shù)據(jù)庫,在真正成為一個PO之后,才具備addMate的資格。

          你必須這樣來操作:

          java代碼: 

           1 Cat cat = new Cat();
           2 cat.setXXX();
           3 daoimpl.addCat(cat);
           4 daoimpl.addMate(cat, mate);



          先持久化cat,然后才能對cat進(jìn)行其他的持久化操作。因此要求業(yè)務(wù)層的程序員必須清楚cat對象處于何種狀態(tài),到底是第一種,還是第三種。如果是第一種,就要先save,再addMate;如果是第三種,就直接addMate。

          但是最致命的是,如果整個軟件分層很多,業(yè)務(wù)層的程序員他拿到這個cat對象也可能是上層Web應(yīng)用層傳遞過來的cat,他自己也不知道這個cat究竟是VO,沒有被持久化過,還是已經(jīng)被持久化過,那么他根本就沒有辦法寫程序了。

          所以這樣的DAOImpl顯然是有問題的,它會對業(yè)務(wù)層的程序員造成很多編程上的陷阱,業(yè)務(wù)層的程序員必須深刻的了解他調(diào)用的每個DAO對PO對象進(jìn)行了何種狀態(tài)管理,必須深刻的了解他的PO對象在任何時候處于什么確切的狀態(tài),才能保證編程的正確性,顯然這是做不到的,但是有了saveOrUpdate,這些問題就迎刃而解了。

          現(xiàn)在你需要修改addMate方法:

          java代碼: 

          1 public void addMate(Cat cat, Mate mate) {
           2     Session session = ...;
           3     Transacton tx = ...;
           4     session.saveOrUpdate(cat);
           5     cat.addMate(mate);
           6     tx.commit();
           7     session.close();
           8 };



          如上,如果業(yè)務(wù)層的程序員傳進(jìn)來的是一個已經(jīng)持久化過的PO對象,那么Hibernate會更新cat對象(假設(shè)業(yè)務(wù)層的程序員在Session外面修改過cat的屬性),如果傳進(jìn)來的是一個新new出來的對象,那么向數(shù)據(jù)庫save這個PO對象。

          BTW: Hibernate此時究竟采取更新cat對象,還是save cat對象,取決于unsave-value的設(shè)定。

          這樣,業(yè)務(wù)層的程序員就不必再操心PO的狀態(tài)問題了,對于他們來說,不管cat是new出來的對象,只是一個VO也好;還是從數(shù)據(jù)庫查詢出來的的PO對象也好,全部都是直接addMate就OK了:

          posted @ 2006-03-02 20:44 killvin| 編輯 收藏

          今天同事問我Struts如何解決文件上傳的問題,一時間沒有想起來,就到google查了一下,果然在Struts Wiki上就有非常詳細(xì)的解釋,抄錄如下,詳細(xì)的請看(http://wiki.apache.org/struts/StrutsFileUpload)



          StrutsFileUpload
          File Upload - Simple Example
          HTML
          This isn't specific to Struts, but gives a simple example of the HTML required to upload a single file.

          Two things are needed in the html page. Firstly, the form needs to specify an enctype of multipart/form-data and secondly an form control of type file.

          JSP
          The above HTML can be generated using the Struts tags in the following way

          <html:form action="/uploadMyFile.do" enctype="multipart/form-data">

          Select File: <html:file property="myFile">

          <html:submit value="Upload File"/>

          </html:form>

          ActionForm
          The ActionForm needs a property of type FormFile.

          Regular ActionForms
          import org.apache.struts.upload.FormFile;

          public class MyActionForm extends ActionForm {

          private FormFile myFile;

          public void setMyFile(FormFile myFile) {
          this.myFile = myfile;
          }

          public FormFile getMyFile() {
          return myFile;
          }
          }

          Dyna ActionForms
          In the struts-config.xml

          <form-bean name="myForm" type="org.apache.struts.action.DynaActionForm">
          <form-property name="myFile" type="org.apache.struts.upload.FormFile"/>
          </form-bean>

          Whats Needed in the Action
          Nothing special really, just retrieve the FormFile from the ActionForm, as you would any other property, and process it as you like. You can get the file name, size and file contents from the FormFile.

          public ActionForward execute(ActionMapping mapping,
          ActionForm form,
          HttpServletRequest request,
          HttpServletResponse response) throws Exception {

          MyActionForm myForm = (MyActionForm)form;

          // Process the FormFile
          FormFile myFile = myForm.getMyFile();
          String contentType = myFile.getContentType();
          String fileName = myFile.getFileName();
          int fileSize = myFile.getFileSize();
          byte[] fileData = myFile.getFileData();
          ...
          }

          File Upload Configuration
          The following parameters can be set in the <controller> element of the struts-config.xml to configure file upload:

          bufferSize - The size (in bytes) of the input buffer used when processing file uploads. Default is 4096.

          maxFileSize - The maximum size (in bytes) of a file to be accepted as a file upload. Can be expressed as a number followed by a "K", "M", or "G", which are interpreted to mean kilobytes, megabytes, or gigabytes, respectively. Default is 250M.

          multipartClass - The fully qualified Java class name of the multipart request handler class to be used with this module. Defaults is org.apache.struts.upload.CommonsMultipartRequestHandler.

          tempDir - Temporary working directory to use when processing file uploads.

          Above taken from the Configuration section in the User Guide.

          Plugging in an Alternative File Upload Mechanism
          By default Struts uses Commons File Upload.

          Alternative implementations can be plugged as long as they implement the org.apache.struts.upload.MultipartRequestHandler interface and Struts configured to use that implementation by specifying it in the multipartClass parameter in the <controller> element of the struts-config.xml

          Fair Warning: The MultipartRequestHandler interface is almost certain to change in a Struts 1.3 or higher release.

          posted @ 2006-03-02 20:43 killvin| 編輯 收藏

                  以前總是認(rèn)為php只是一種jsp的翻版,沒有啥意思!不象J2EE的體系結(jié)構(gòu)那樣,有應(yīng)用服務(wù)器的概念,只是一個簡單的服務(wù)器腳本,而昨天的看法卻讓我大跌眼鏡,其實(shí)php和java、python都處在一個層次上,甚至比java更有優(yōu)勢!不應(yīng)該僅僅只是將php和jsp看作是同樣的檔次,這就好比是告訴寫python的程序員,你們開發(fā)不了應(yīng)用程序一樣的讓別人笑掉大牙,甚至懷疑你的腦子有毛病,zope就是一個很好的例子!!優(yōu)秀的應(yīng)用服務(wù)器,就是用Python開發(fā)的!
                  
                  我們更應(yīng)該將php看作是一個語言,和python同樣優(yōu)秀(當(dāng)然php和python的定位不同,也就是因?yàn)檫@樣的定位,而讓人產(chǎn)生的錯覺!!)如果Php將自己定位如python一樣!并在語言這個級別更貼近面向?qū)ο蟮乃季S模式,那Python也許就不會如此的火爆!
                  
                  看來php之父并沒有將語言向python靠攏的意思,也就是說這樣的語言目前的生存空間僅僅只限于服務(wù)器端的腳本!這是它的領(lǐng)地!但除非是它閉著眼鏡,不然沒有人會愿意看到html的代碼里寫這<?php>這樣的代碼!這就好比是在沒有webwork 、struts這樣優(yōu)秀的web框架出現(xiàn)之前,jsp讓人惡心的原因,如果Php的領(lǐng)域沒有這樣的MVC框架出現(xiàn),那我情愿還是選擇jsp!!出于學(xué)習(xí)我會選擇Python,但永遠(yuǎn)不會選擇php......
                  
                  告訴我你知道的php世界里優(yōu)秀的web框架!也許我會改變看法!但我不會選擇重新發(fā)明輪子!!

           

          posted @ 2006-03-02 20:26 killvin| 編輯 收藏

          Thinking in Python

          You can download the current version of Thinking in Python here. This includes the BackTalk comment collection system that I built in Zope.

          The page describing this project is here.

          The current version of the book is 0.1. This is a preliminary release; please note that not all the chapters in the book have been translated.

          The source code is in the download package. When you unzip everything (remember to use the -a flag if you're on Unix), the code will be put into subdirectories for each chapter.

          This is not an introductory Python book. This book assumes you've learned the basics of Python elsewhere. I personally like Learning Python by Lutz & Ascher, from O'Reilly. Although it does not cover all the Python 2.0, 2.1 and 2.2 features that I use in this book, most books don't at this point.

          However, Learning Python is not exactly a beginning programmer's book, either (although it's possible if you're dedicated). If you're just getting started with programming you might try the free, downloadable A Byte of Python.

          posted @ 2006-03-02 20:23 killvin| 編輯 收藏

          僅列出標(biāo)題
          共5頁: 上一頁 1 2 3 4 5 下一頁 
          主站蜘蛛池模板: 临澧县| 克东县| 铜鼓县| 汝城县| 巍山| 香港| 长顺县| 墨玉县| 云林县| 商都县| 绥滨县| 读书| 甘德县| 乐业县| 农安县| 军事| 化州市| 突泉县| 苍梧县| 壶关县| 惠来县| 页游| 苍山县| 梁河县| 偏关县| 鄄城县| 青川县| 彭阳县| 梅河口市| 沙坪坝区| 都兰县| 五寨县| 怀仁县| 扎兰屯市| 叙永县| 梁河县| 田林县| 扶沟县| 松溪县| 阿城市| 南投县|