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

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

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

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    最近比較忙,工作上和生活上都是,小結下:
    1.最近主要工作是接手了一些郵箱系統的開發工作,JavaMail倒是越來越熟悉了,碰到一個問題需要注意下,使用imap協議訪問郵件服務器,我在本機jboss和測試環境websphere上測試正常,一放到生產環境下就出問題,后浪費我周末半天的時間檢查才發現,imap默認的LOGIN登錄是使用文本方式登錄,不需要認證,在本機和測試環境都普通的LOGIN方式(有安全隱患的方式),在正式環境的環境變量卻設置為PLAIN認證,導致登錄失敗,改正下:
        props.setProperty("mail.imap.auth.plain.disable""true");
    禁止掉認證即可,還有一些變量設置可以在j2ee api doc里查到。說到底還是對協議的不熟悉就投入開發。


    2.過去辦公自動化系統的文檔顯示局限在word類型,今天弄了個新的ActiveX控件,自動更新或者安裝ActiveX控件,只要設置下CODEBASE即可,比如:
    <OBJECT id="AutoVueX" classid="clsid:B6FCC215-D303-11D1-BC6C-0000C078797F" CODEBASE="http://localhost/xxxx"./>

    3.讀很多開源項目,動態加載配置文件是一個常見的技巧,最近也應用了下,沒什么技術含量,僅記錄下。原理就是通過判斷File類的lastModified()得到修改時間與內存中保存的最近修改時間進行比較,如果大于就讀入配置文件重新設置配置信息:
    private static void checkConfigModify() {
            File file 
    = new File(MailConnectionManager.class.getResource(
                    MailConstants.CONFIG_FILE).getFile());
            
    //如果有修改,重新加載配置文件信息
            if (file.lastModified() > MailConstants.last_modified) {
                MailConstants.last_modified 
    = file.lastModified();
                setConfig();
            }
        }

        
    private static void setConfig() {
            InputStream is 
    = null;
            
    try {
                Properties properties 
    = new Properties();
                is 
    = MailConnectionManager.class
                        .getResourceAsStream(MailConstants.CONFIG_FILE);
                properties.load(is);
                MailConstants.USERNAME 
    = properties.getProperty("username");
                MailConstants.HOST 
    = properties.getProperty("host");
                MailConstants.PASSWORD 
    = properties.getProperty("password");

                System.out
                        .println(
    "配置文件被修改,重新加載配置文件成功!");
                StringBuffer sb 
    = new StringBuffer("username:");
                sb.append(MailConstants.USERNAME).append(
    "   host:")
                        .append(
    "host:").append(MailConstants.HOST);
                
    if (MailConstants.PASSWORD != null)
                    sb.append(
    "     ").append("password:not null");
                
    else
                    sb.append(
    "     password:null");
                System.out.println(sb.toString());
            } 
    catch (Exception e) {
                e.printStackTrace();
            } 
    finally {
                
    if (is != null)
                    
    try {
                        is.close();
                    } 
    catch (IOException e2) {
                        e2.printStackTrace();
                    }
            }
        }

    比較值的注意的就是Class類的getResource和getResourceAsStream方法,當然也可以使用ResourceBundle

    4.最近將項目中過去別人寫的簡單工作流引擎分析了一下,顧名思義,是很簡單,采用數據庫作為流程定義的存儲介質,流程定義也是在web上操作,僅支持順序、選擇、并行路由,簡單的或、與條件選擇,因為只是作為沒有復雜流程的公文流轉系統,倒是符合客戶要求。模型也是基于狀態機。復雜的條件運算是沒辦法做到,沒有采用BeanShell的腳本語言也是個原因。Jruby到1.0了,今天下載了,有空看看。工作流采用Petri網建模是趨勢,可惜那本書我還沒讀完。

    5.spring如何得到FactroyBean本身?我們知道實現FactroyBean接口的getObject方法,返回的就是getObject返回的bean,而如何得到FactoryBean本身呢?答案是加上一個符號&
    factory.getBean("&TestFactoryBean");


    6.SICP讀到2.2節,準備等習題全做完了再一起發上來,忙,讀的慢了。老婆的堂妹來了,租的房子只有一張床,只在這地方呆一年,可不想再買張床,我只好回公司宿舍!-_-
    廢話不說,回家了。



    posted @ 2007-06-11 19:45 dennis 閱讀(1260) | 評論 (0)編輯 收藏

        最近javaeye有個帖子好熱:玩個接龍吧,當年的高考成績 ,也回想起了自己的高中生活。現在想想,其實高中那三年,前兩年還是蠻快樂的,有新東西要學,有新同學可以認識。而且那時自己實在是太簡單了,剛從農村中學來到全縣最好的學校,對外面的世界基本半懂不懂,只對書感興趣,必須要承認,除了大學三年看的書之外,中學是我看書最多的一個時期,我把我外婆的家的書基本搬了過來,把我在讀大學的三舅在圖書館借的書也搞過來,看了N多雜書,甚至有段時間竟然去啃外公留下來的《馬克思恩格斯全集》。
        在高中另一件重要的事情是我熱愛上了足球,和兄弟們踢球的日子實在讓人懷念,就算是高三的時候,我們也在每天放學后踢上幾腳球。不過學校后來把足球場改造成了籃球場,我們只有在水泥地上踢球了。前幾年的某次高中同學聚會,我們還特意去那塊水泥地上踢球,好久未動,稍微跑幾步氣喘吁吁,遺憾。而上了大學后,我基本沒怎么踢球了,網吧、圖書館是我活動的兩個主要地方,球場只在大一的時候去過幾回,買了的足球也在我退學后不知道遺忘在宿舍的哪個角落。
        我的中學時代確實是熱愛學習的,熱愛知識的。那時的我對數學非常感興趣,我的學習步伐總在老師教學的前面,后來發現學無可學,我就去讀高等數學,搞懂了高等數學第一冊(高等教育出版社出版的那個),然后參加了全國高中數學競賽(好像是這個名字),貌似還得了個優秀獎,我記的自己是用微積分是解決里面的題目,可惜老師跟我說用微積分是不能得分的!-_-。高等數學,這也是我在墮落的三年大學生涯里面唯一稍微認真上過的一門課吧。關于我的大學,那是另一個話題,一個成語來形容就是:水深火熱。可憐我對學習的興趣完全毀在了無窮無盡的做題上了,我現在想起高二高三時兩天一小考、三天一大考,無數的練習題的日子就范惡心,我徹底討厭學習了,我要承認,在高三的開始的時候就有嚴重的厭學情緒,甚至高三的時候我竟然課堂上公然看武校小說,也在那段時間讀完了古龍和黃易,呵呵。這也為我高考的失敗埋下了伏筆。
        高中的我是虛榮的,甚至可以說是驕傲的,呵呵,一直自我感覺良好,從小到大也沒什么比較嚴重的打擊,現在想想為自己汗顏。虛榮是最大的原罪。很遺憾那時的自己沒有意識到這一點,畢竟也沒有人會告訴我這一點。這也是性格決定命運,在大學的墮落沒什么借口好找。很慶幸自己能從那落魄的三年里走了出來,現在的我會好好走好自己的路。
        扯遠了,高三雖然說自己很厭學,可成績也一直在年段前三的左右,沒什么危機感,也沒什么緊迫感,更不用提什么目標和激情,那時就想趕緊考試吧,逃離這個地方,去一個沒有人認識我的地方重新開始我的大學生涯。那時還在幻想大學也許真是個有趣的地方,當然,大學是個什么鬼地方大伙都知道了。高考那幾天糊里糊涂就過了,我自己有預感沒考好,預測的分數也證明了這一點,我倒是沒多大在意。填報志愿的時候跟老師咨詢了下,呵呵,還是填錯了。不過那時我也不明確自己的興趣在哪,填的時候完全是盲目的,后來第一志愿沒上,上了第二志愿的某211學校的環境資源學院,我沒填這個專業,可惜第二志愿的我沒有選擇的余地,盡管分數遠遠高過我后來想讀的計算機專業,這就是現實。說不后悔,那是不可能的,遺憾的是自己沒有機會再去學校學習自己感興趣的東西,現在只有靠自己自學計算機科學基礎,一點一點地前進吧。
        不再好高騖遠,不再有離奇的夢想,這就是現在的我。寫著寫著怎么感覺像在寫作文,哈哈。

    posted @ 2007-06-08 10:35 dennis 閱讀(590) | 評論 (1)編輯 收藏

         昨天搞了動態自動加載配置文件,又遇到路徑問題,找到這篇很棒的文章,收藏一下,來自http://java.chinaitlab.com/base/532062_3.html
          前言
          Java的路徑問題,非常難搞。最近的工作涉及到創建和讀取文件的工作,這里我就給大家徹底得解決Java路徑問題。
          我編寫了一個方法,比 ClassLoader.getResource(String 相對路徑)方法的能力更強。它可以接受“../”這樣的參數,允許我們用相對路徑來定位classpath外面的資源。這樣,我們就可以使用相對于 classpath的路徑,定位所有位置的資源!
           
          Java路徑
          Java中使用的路徑,分為兩種:絕對路徑和相對路徑。具體而言,又分為四種:
          一、URI形式的絕對資源路徑
          如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b
          URL是URI的特例。URL的前綴/協議,必須是Java認識的。URL可以打開資源,而URI則不行。
          URL和URI對象可以互相轉換,使用各自的toURI(),toURL()方法即可!
          
          二、本地系統的絕對路徑
          D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b
          Java.io包中的類,需要使用這種形式的參數。
          但是,它們一般也提供了URI類型的參數,而URI類型的參數,接受的是URI樣式的String。因此,通過URI轉換,還是可以把URI樣式的絕對路徑用在java.io包中的類中。
          
          三、相對于classpath的相對路徑
          如:相對于
          file:/D:/java/eclipse32/workspace/jbpmtest3/bin/這個路徑的相對路徑。其中,bin是本項目的classpath。所有的Java源文件編譯后的.class文件復制到這個目錄中。
          
          
          四、相對于當前用戶目錄的相對路徑
          就是相對于System.getProperty("user.dir")返回的路徑。
          對于一般項目,這是項目的根路徑。對于JavaEE服務器,這可能是服務器的某個路徑。這個并沒有統一的規范!
          所以,絕對不要使用“相對于當前用戶目錄的相對路徑”。然而:
          默認情況下,java.io 包中的類總是根據當前用戶目錄來分析相對路徑名。此目錄由系統屬性 user.dir 指定,通常是 Java 虛擬機的調用目錄。
          這就是說,在使用java.io包中的類時,最好不要使用相對路徑。否則,雖然在J2SE應用程序中可能還算正常,但是到了J2EE程序中,一定會出問題!而且這個路徑,在不同的服務器中都是不同的!
          
          相對路徑最佳實踐
          推薦使用相對于當前classpath的相對路徑
          因此,我們在使用相對路徑時,應當使用相對于當前classpath的相對路徑。
          ClassLoader類的getResource(String name),getResourceAsStream(String name)等方法,使用相對于當前項目的classpath的相對路徑來查找資源。
          讀取屬性文件常用到的ResourceBundle類的getBundle(String path)也是如此。
          通過查看ClassLoader類及其相關類的源代碼,我發現,它實際上還是使用了URI形式的絕對路徑。通過得到當前classpath的URI形式的絕對路徑,構建了相對路徑的URI形式的絕對路徑。(這個實際上是猜想,因為JDK內部調用了SUN的源代碼,而這些代碼不屬于JDK,不是開源的。)
          
          相對路徑本質上還是絕對路徑
          因此,歸根結底,Java本質上只能使用絕對路徑來尋找資源。所有的相對路徑尋找資源的方法,都不過是一些便利方法。不過是API在底層幫助我們構建了絕對路徑,從而找到資源的!
          
          得到classpath和當前類的絕對路徑的一些方法
              下面是一些得到classpath和當前類的絕對路徑的一些方法。你可能需要使用其中的一些方法來得到你需要的資源的絕對路徑。
          1,FileTest.class.getResource("")
          得到的是當前類FileTest.class文件的URI目錄。不包括自己!
          如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/com/test/
          2,FileTest.class.getResource("/")
          得到的是當前的classpath的絕對URI路徑。
          如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
          3,Thread.currentThread().getContextClassLoader().getResource("")
          得到的也是當前ClassPath的絕對URI路徑。
          如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
          4,FileTest.class.getClassLoader().getResource("")
          得到的也是當前ClassPath的絕對URI路徑。
          如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
          5,ClassLoader.getSystemResource("")
          得到的也是當前ClassPath的絕對URI路徑。
          如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
            
          我推薦使用Thread.currentThread().getContextClassLoader().getResource("")來得到當前的classpath的絕對路徑的URI表示法。
          
          Web應用程序中資源的尋址
              上文中說過,當前用戶目錄,即相對于System.getProperty("user.dir")返回的路徑。
          對于JavaEE服務器,這可能是服務器的某個路徑,而不是我們發布的Web應用程序的根目錄!這個并沒有統一的規范!
          這樣,在Web應用程序中,我們絕對不能使用相對于當前用戶目錄的相對路徑。
          在Web應用程序中,我們一般通過ServletContext.getRealPath("/")方法得到Web應用程序的根目錄的絕對路徑。
          這樣,我們只需要提供相對于Web應用程序根目錄的路徑,就可以構建出定位資源的絕對路徑。
          這是我們開發Web應用程序時一般所采取的策略。
          
          通用的相對路徑解決辦法
          Java中各種相對路徑非常多,不容易使用,非常容易出錯。因此,我編寫了一個便利方法,幫助更容易的解決相對路徑問題。
          
          Web應用程序中使用JavaSE運行的資源尋址問題
          在JavaSE程序中,我們一般使用classpath來作為存放資源的目的地。但是,在Web應用程序中,我們一般使用classpath外面的WEB-INF及其子目錄作為資源文件的存放地。
          在Web應用程序中,我們一般通過ServletContext.getRealPath("/")方法得到Web應用程序的根目錄的絕對路徑。這樣,我們只需要提供相對于Web應用程序根目錄的路徑,就可以構建出定位資源的絕對路徑。
          Web應用程序,可以作為Web應用程序進行發布和運行。但是,我們也常常會以JavaSE的方式來運行Web應用程序的某個類的main方法。或者,使用JUnit測試。這都需要使用JavaSE的方式來運行。
          這樣,我們就無法使用ServletContext.getRealPath("/")方法得到Web應用程序的根目錄的絕對路徑。
          而JDK提供的ClassLoader類,它的getResource(String name),getResourceAsStream(String name)等方法,使用相對于當前項目的classpath的相對路徑來查找資源。
          讀取屬性文件常用到的ResourceBundle類的getBundle(String path)也是如此。
          它們都只能使用相對路徑來讀取classpath下的資源,無法定位到classpath外面的資源。
          Classpath外配置文件讀取問題
          如,我們使用測試驅動開發的方法,開發Spring、Hibernate、iBatis等使用配置文件的Web應用程序,就會遇到問題。
          盡管Spring自己提供了FileSystem(也就是相對于user,dir目錄)來讀取Web配置文件的方法,但是終究不是很方便。而且與Web程序中的代碼使用方式不一致!
          至于Hibernate,iBatis就更麻煩了!只有把配置文件移到classpath下,否則根本不可能使用測試驅動開發!
          
              這怎么辦?


          通用的相對路徑解決辦法
          面對這個問題,我決定編寫一個助手類ClassLoaderUtil,提供一個便利方法[public static URL getExtendResource(String relativePath)]。在Web應用程序等一切Java程序中,需要定位classpath外的資源時,都使用這個助手類的便利方法,而不使用 Web應用程序特有的ServletContext.getRealPath("/")方法來定位資源。
          
          利用classpath的絕對路徑,定位所有資源
          這個便利方法的實現原理,就是“利用classpath的絕對路徑,定位所有資源”。
          ClassLoader類的getResource("")方法能夠得到當前classpath的絕對路徑,這是所有Java程序都擁有的能力,具有最大的適應性!
          而目前的JDK提供的ClassLoader類的getResource(String 相對路徑)方法,只能接受一般的相對路徑。這樣,使用ClassLoader類的getResource(String 相對路徑)方法就只能定位到classpath下的資源。
          如果,它能夠接受“../”這樣的參數,允許我們用相對路徑來定位classpath外面的資源,那么我們就可以定位位置的資源!
          當然,我無法修改ClassLoader類的這個方法,于是,我編寫了一個助手類ClassLoaderUtil類,提供了[public static URL getExtendResource(String relativePath)]這個方法。它能夠接受帶有“../”符號的相對路徑,實現了自由尋找資源的功能。
          
          通過相對classpath路徑實現自由尋找資源的助手類的源代碼:
        
          import java.io.IOException;
          
    import java.io.InputStream;
          
    import java.net.MalformedURLException;
          
    import java.net.URL;
          
    import java.util.Properties;
          
          
    import org.apache.commons.logging.Log;
          
    import org.apache.commons.logging.LogFactory;
          
          
    /**
           *@author沈東良shendl_s@hotmail.com
           *Nov29,2006 10:34:34AM
           *用來加載類,classpath下的資源文件,屬性文件等。
           *getExtendResource(StringrelativePath)方法,可以使用../符號來加載classpath外部的資源。
           
    */
          publicclass ClassLoaderUtil {
              privatestatic Log log
    =LogFactory.getLog(ClassLoaderUtil.class);
              
    /**
               *Thread.currentThread().getContextClassLoader().getResource("")
               
    */
            
              
    /**
               *加載Java類。 使用全限定類名
               *@paramclassName
               *
    @return
               
    */
              publicstatic Class loadClass(String className) {
                  
    try {
                    
    return getClassLoader().loadClass(className);
                  } 
    catch (ClassNotFoundException e) {
                    thrownew RuntimeException(
    "class not found '"+className+"'", e);
                  }
               }
               
    /**
                 *得到類加載器
                 *
    @return
                 
    */
               publicstatic ClassLoader getClassLoader() {
              
                  
    return ClassLoaderUtil.class.getClassLoader();
               }
               
    /**
                 *提供相對于classpath的資源路徑,返回文件的輸入流
                 *@paramrelativePath必須傳遞資源的相對路徑。是相對于classpath的路徑。如果需要查找classpath外部的資源,需要使用../來查找
                 *
    @return 文件輸入流
               *@throwsIOException
               *@throwsMalformedURLException
                 
    */
               publicstatic InputStream getStream(String relativePath) 
    throws MalformedURLException, IOException {
                   
    if(!relativePath.contains("../")){
                       
    return getClassLoader().getResourceAsStream(relativePath);
                      
                   }
    else{
                       
    return ClassLoaderUtil.getStreamByExtendResource(relativePath);
                   }
                
               }
               
    /**
                 *
                 *@paramurl
                 *
    @return
                 *@throwsIOException
                 
    */
               publicstatic InputStream getStream(URL url) 
    throws IOException{
                   
    if(url!=null){
                      
                          
    return url.openStream();
                    
                      
                   }
    else{
                       returnnull;
                   }
               }
               
    /**
                 *
                 *@paramrelativePath必須傳遞資源的相對路徑。是相對于classpath的路徑。如果需要查找classpath外部的資源,需要使用../來查找
                 *
    @return
                 *@throwsMalformedURLException
                 *@throwsIOException
                 
    */
               publicstatic InputStream getStreamByExtendResource(String relativePath) 
    throws MalformedURLException, IOException{
                  
    return ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));
                  
                  
               }
              
                
    /**
                 *提供相對于classpath的資源路徑,返回屬性對象,它是一個散列表
                 *@paramresource
                 *
    @return
                 
    */
               publicstatic Properties getProperties(String resource) {
                  Properties properties 
    = new Properties();
                  
    try {
                    properties.load(getStream(resource));
                  } 
    catch (IOException e) {
                    thrownew RuntimeException(
    "couldn't load properties file '"+resource+"'", e);
                  }
                  
    return properties;
               }
               
    /**
                 *得到本Class所在的ClassLoader的Classpat的絕對路徑。
                 *URL形式的
                 *
    @return
                 
    */
               publicstatic String getAbsolutePathOfClassLoaderClassPath(){
                  
                  
                   ClassLoaderUtil.log.info(ClassLoaderUtil.getClassLoader().getResource(
    "").toString());
                   
    return ClassLoaderUtil.getClassLoader().getResource("").toString();
                  
               }

               
    /**
                 *
                 *@paramrelativePath 必須傳遞資源的相對路徑。是相對于classpath的路徑。如果需要查找classpath外部的資源,需要使用../來查找
                 *@return資源的絕對URL
               *@throwsMalformedURLException
                 
    */
               publicstatic URL getExtendResource(String relativePath) 
    throws MalformedURLException{
              
                   ClassLoaderUtil.log.info(
    "傳入的相對路徑:"+relativePath) ;
                   
    //ClassLoaderUtil.log.info(Integer.valueOf(relativePath.indexOf("../"))) ;
                   if(!relativePath.contains("../")){
                       
    return ClassLoaderUtil.getResource(relativePath);
                      
                   }
                   String classPathAbsolutePath
    =ClassLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
                   
    if(relativePath.substring(01).equals("/")){
                       relativePath
    =relativePath.substring(1);
                   }
                   ClassLoaderUtil.log.info(Integer.valueOf(relativePath.lastIndexOf(
    "../"))) ;
                
                   String wildcardString
    =relativePath.substring(0,relativePath.lastIndexOf("../")+3);
                  relativePath
    =relativePath.substring(relativePath.lastIndexOf("../")+3);
                   
    int containSum=ClassLoaderUtil.containSum(wildcardString, "../");
                   classPathAbsolutePath
    = ClassLoaderUtil.cutLastString(classPathAbsolutePath, "/", containSum);
                   String resourceAbsolutePath
    =classPathAbsolutePath+relativePath;
                   ClassLoaderUtil.log.info(
    "絕對路徑:"+resourceAbsolutePath) ;
                   URL resourceAbsoluteURL
    =new URL(resourceAbsolutePath);
                   
    return resourceAbsoluteURL;
               }
               
    /**
                *
                 *@paramsource
                 *@paramdest
                 *
    @return
                 
    */
               privatestaticint containSum(String source,String dest){
                   
    int containSum=0;
                   
    int destLength=dest.length();
                   
    while(source.contains(dest)){
                       containSum
    =containSum+1;
                       source
    =source.substring(destLength);
                      
                   }
                  
                  
                   
    return containSum;
               }
               
    /**
                 *
                 *@paramsource
                 *@paramdest
                 *@paramnum
                 *
    @return
                 
    */
               privatestatic String cutLastString(String source,String dest,
    int num){
                   
    // String cutSource=null;
                   for(int i=0;i<num;i++){
                       source
    =source.substring(0, source.lastIndexOf(dest, source.length()-2)+1);
                      
                      
                   }
                  
                  
                  
                   
    return source;
               }
               
    /**
                 *
                 *@paramresource
                 *
    @return
                 
    */
                publicstatic URL getResource(String resource){
                ClassLoaderUtil.log.info(
    "傳入的相對于classpath的路徑:"+resource) ;
                   
    return ClassLoaderUtil.getClassLoader().getResource(resource);
               }
             
          
              
          
              
    /**
               *@paramargs
               *@throwsMalformedURLException
               
    */
              publicstaticvoid main(String[] args) 
    throws MalformedURLException {
                
                      
    //ClassLoaderUtil.getExtendResource("../spring/dao.xml");
                  
    //ClassLoaderUtil.getExtendResource("../../../src/log4j.properties");
                  ClassLoaderUtil.getExtendResource("log4j.properties");
                
                  System.out.println(ClassLoaderUtil.getClassLoader().getResource(
    "log4j.properties").toString());
          
              }
          
          }

          
          后記
          ClassLoaderUtil類的public static URL getExtendResource(String relativePath),雖然很簡單,但是確實可以解決大問題。
          不過這個方法還是比較簡陋的。我還想在未來有空時,進一步增強它的能力。比如,增加Ant風格的匹配符。用**代表多個目錄,*代表多個字符,?代表一個字符。達到Spring那樣的能力,一次返回多個資源的URL,進一步方便大家開發。
          
          總結:
          1,盡量不要使用相對于System.getProperty("user.dir")當前用戶目錄的相對路徑。這是一顆定時炸彈,隨時可能要你的命。
          2,盡量使用URI形式的絕對路徑資源。它可以很容易的轉變為URI,URL,File對象。
          3,盡量使用相對classpath的相對路徑。不要使用絕對路徑。使用上面ClassLoaderUtil類的 public static URL getExtendResource(String relativePath)方法已經能夠使用相對于classpath的相對路徑定位所有位置的資源。
          4,絕對不要使用硬編碼的絕對路徑。因為,我們完全可以使用ClassLoader類的getResource("")方法得到當前classpath的絕對路徑。
          使用硬編碼的絕對路徑是完全沒有必要的!它一定會讓你死的很難看!程序將無法移植!
          如果你一定要指定一個絕對路徑,那么使用配置文件,也比硬編碼要好得多!
          當然,我還是推薦你使用程序得到classpath的絕對路徑來拼資源的絕對路徑!

      


    posted @ 2007-06-08 08:40 dennis 閱讀(1490) | 評論 (0)編輯 收藏

        泛型引入java語言已經有很長一段時間了,在JDK5出來的時候也非常認真地學習過,不過學習的資料都是網上泛濫并且重復的教程。這幾天下了《The Java Programming Language》的第4版,準備把jdk5引入的新東西再重新系統地學習一次,同時再次回顧下java基礎。今天記錄下學習泛型那一章的注意點。
    一、泛型類型的聲明
    1.需要著重注意的一點,比如聲明類Cell<E>:
    package net.rubyeye.javaprogramming.generic;

    public class Cell<E> {
        
    private Cell<E> next;

        
    private E element;

        
    public Cell(E element) {
            
    this.element = element;
        }

        
    public Cell(E element, Cell<E> next) {
            
    this.next = next;
            
    this.element = element;
        }

        
    public E getElement() {
            
    return element;
        }

        
    public void setElement(E element) {
            
    this.element = element;
        }

        
    public Cell<E> getNext() {
            
    return next;
        }

        
    public void setNext(Cell<E> next) {
            
    this.next = next;
        }

    }

    然后如此使用:
    Cell<String> strCell = new Cell<String>("Hello");
    Cell
    <Integer> intCell = new Cell<Integer>(25);

    那么Cell<String>和Cell<Integer>是兩個類嗎?不,他們是同一個類,通過下面的實驗證明:
    assertTrue(strCell.getClass() == intCell.getClass()));

    java泛型的實現采用的“擦拭法”,Cell<E>仍然是一個類,無論E被任何具體的類型所替代。

    2.泛型的類型參數不能用于static變量、static方法和static初始化,比如下面的使用方式都不能編譯通過:
    public class Cell<E> {
        
    private static Cell<E> next;
        
        
    private static void test(E e){
            
        }
       
    同樣,靜態方法是與類相關聯的,調用也只能通過類,假設Cell有一個靜態方法test,怎么調用才是正確的呢?
    Cell<E>.test();  //編譯錯誤
    Cell<String>.test();  //同樣編譯錯誤
    Cell.test();  //正確的方式
    類似的,泛型的類型參數不能用于聲明數組類型,比如下面的代碼同樣無法編譯通過:
    class SingleLinkQueue<E> {
        
    // 
        public E[] toArray() {
        
    //
        }
    }

    3.類型參數可以繼承其他的類和接口,如果有多個接口可以用&符號連接,通過extend參數限制了類型參數的范圍,比如:
    interface SortedCharSeqCollection<extends Comparable<E>
                                      
    & CharSequence> {
        
    //  sorted char sequence collection methods 
    }

    SortedCharSeqCollection的類型參數E強制繼承自Comparable和CharSequence接口,也就是替代的具體的類型參數必須實現這兩個接口,從而限制了類型參數(type parameter)。

    4.比較有趣的內部類的泛型,對于靜態內部類的類型參數可以與外部類的類型參數名不一樣,靜態內部類的類型參數與外部類的類型參數其實沒有一點關系,比如:
    class SingleLinkQueue<E> {
        
    static class Cell<E> {
            
    private Cell<E> next;
            
    private E element;
            
    public Cell(E element) {
                
    this.element = element;
            }
            
    public Cell(E element, Cell<E> next) {
                
    this.element = element;
                
    this.next = next;
            }
            
    public E getElement() {
                
    return element;
            }
            
    /*  rest of Cell methods as before  */
        }

        
    protected Cell<E> head;
        
    protected Cell<E> tail;

        
    /*  rest of SingleLinkQueue methods as before  */
    }


    Cell<E>類的聲明和SingleLinkQueue<E> 兩個類中的E僅僅是名稱相同,他們之間的關聯是通過head和tail的聲明才關聯在一起,你可以將Cell<E>中的E改成F也沒關系,比如:
    package net.rubyeye.javaprogramming.generic;

    class AnotherSingleLinkQueue<E> {
        
    static class Cell<F> {
            
    private Cell<F> next;

            
    private F element;

            
    public Cell(F element) {
                
    this.element = element;
            }

            
    public Cell(F element, Cell<F> next) {
                
    this.element = element;
                
    this.next = next;
            }

            
    public F getElement() {
                
    return element;
            }
            
    /*  rest of Cell methods as before  */
        }

        
    protected Cell<E> head;

        
    protected Cell<E> tail;

        
    /*  rest of SingleLinkQueue methods as before  */
    }

    而一般的內部類就不一樣了,內部類可以直接使用外部類的類型參數甚至隱藏。

    二、子類型與通配符
    今天讀了第2節,泛型的使用比我原先所知的更為復雜,java語法本來以簡潔優美著稱,隨著java5,java7的到來,語法是越來越復雜,甚至可以說丑陋!-_-

        要知道一點,比如List<Integer>不是List<Number>的子類,而是Collection<Integer>的子類。因為List<Integer>和List<Number>的類型是一樣的,都是List。那么如何表示參數化類型是Number的子類呢?這就需要用到通配符:
    List<? extends Number>
    表示類型變量是Number或者Number的子類。這個就是所謂的上界通配符,同樣,如果要表示類型變量是Number或者Number的super type,可以使用下界通配符:
    List<? super Number>

    而通配符List<?>等價于:
    List<? extends Object>

        通配符只能用于變量、局部變量、參數類型和返回類型,不能用于命名類和接口。比如下面的代碼將不能編譯通過:
    class MyList implements List<?>{
       
    //
    }
        通配符有另一個問題:因為通配符代表的是未知的類型,你不能在任何需要類型信息的地方使用它。比如下面的代碼同樣無法編譯通過:
    SingleLinkQueue<?> strings =
        
    new SingleLinkQueue<String>();
    strings.add(
    "Hello");               // INVALID: 無法編譯

    SingleLinkQueue
    <? extends Number> numbers =
        
    new SingleLinkQueue<Number>();
    numbers.add(Integer.valueOf(
    25));   // INVALID: 無法編譯


    三、泛型方法和類型推斷
        如果我們想參數化方法的參數和返回值的類型,這就引出了泛型方法的聲明,聲明一個泛型方法的方式如下:
    <T> T passThrough(T obj) {
        
    return obj;
    }

    這個方法限制傳入的參數的類型與返回的參數類型將一致,可以看到,在方法簽名前加上<T>即可。我們可以這樣調用這個方法:
    String s1 = "Hello";
    String s2 
    = this.<String>passThrough(s1);

    這樣的調用是不是比較奇怪?幸好提供了類型推斷,根據參數的類型來自動判斷方法的類型(比如返回值類型),因此可以直接調用:
    String s1 = "Hello";
    String s2 
    = this.passThrough(s1);

        如果方法有兩個類型變量,類型推斷將怎么處理呢?比如:
    <T> T passThrough(T obj1,T obj2) {
            
    return (T)(obj1.toString()+obj2.toString());
        }

    然后我們傳入兩個參數,一個String,一個int,那么返回什么呢?
    String s1="test";
    String s3
    =this.passThrough(s1, 1);  //編譯出錯
    類型推斷是比較復雜的,這里將返回的將是Object類型,是傳入的參數類型的交集

    posted @ 2007-06-05 17:07 dennis 閱讀(2694) | 評論 (2)編輯 收藏

        好久沒更新blog了,上個星期高燒39度,上醫院滴瓶,吃了3天藥,燒是退下來了,人的精神也散了。天氣越來越熱,老婆在公司又受了委屈就叫她辭了職,昨天晚上又被拉過去喝了好多酒,哎,現在頭昏腦脹的,不,是這兩個星期都過的亂七八糟的,過去的生活節奏都被打亂了。工作沒法專心,書也讀不下去,身體感覺累的慌,天氣又熱的讓人受不了,這兩天上班辦公室的空調又壞了,我是邊扇著風邊寫著這篇blog。是需要好好調整下身體和精神狀態了,今天下了八段錦的視頻,過去上學時經常練,自從出了校門就沒怎么鍛煉了,要調整還是先從身體開始;sicp也要繼續看了,習題也要繼續做;歐洲聯賽都收官了,不必為了看比賽熬夜了,早睡早睡。希望明天別這么熱了,趕緊下雨吧,阿門。

    posted @ 2007-05-29 11:33 dennis 閱讀(650) | 評論 (2)編輯 收藏

        昨天晚上讀了2.1節,今天開始做下習題,這節相當有趣,數據抽象的概念解釋的很清晰。
    習題2.1,make-rat能正確地處理正負數,加幾個判斷條件即可:
    (define (make-rate n d)
      (let ((g (gcd n d)))
        (cond ((or (and (negative? n) (positive? d)) (and (positive? n) (positive? d))) (cons (/ n g) (/ d g)))
              (else
               (cons (opposition (/ n g)) (opposition (/ d g)))))))

    習題2.2,首先定義make-point,x-point,y-point三個過程:
    (define (make-point x y) (cons x y))
    (define (x-point p) (car p))
    (define (y-point p) (cdr p))

    線段是由兩點組成,在此基礎上定義make-segment,start-segment,end-segment過程:
    (define (make-segment s e)
      (cons s e))
    (define (start-segment segment)
      (car segment))
    (define (end-segment segment)
      (cdr segment))

    OK,然后定義題目要求的midpoint-segment求線段中間點坐標:
    (define (midpoint-segment segment)
      (let ((start (start-segment segment))
            (end (end-segment segment)))
        (make-point (/ (+ (x-point start) (x-point end)) 2) (/ (+ (y-point start) (y-point end)) 2))))

    測試一下:
    > (define start (make-point 10 10))
    > (define end (make-point 0 0))
    > (define segment (make-segment start end))
    > (print-point (midpoint-segment segment))

    (5,5)

     習題2.3,這題目主要是考察對過程抽象的理解,對于計算一個矩形的周長和面積來說,需要兩個信息:長度和寬度。因此,首先假設我們已經有3個過程:make-rectang用于創建矩形,width用于返回寬,length用于返回長。那么周長和面積可以寫為:
    (define (perimeter rectang)
      (* 2 (+ (width rectang) (length rectang))))
    (define (area rectang)
      (* (width rectang) (length rectang)))
    具體如何實現make-rectang,width,length3個過程與周長、面積的計算實現了抽象隔離,具體實現的改變不需要修改 perimeter、area兩個過程。矩形可以表示為一條有向線段和距離,有向線段是矩形的一條邊,與它平行的另一條邊的距離是d。因此定義下這三個過 程:
    (define (make-rectang segment d)
        (cons segmeng d))
    (define (length rectang)
       (car rectang))
    (define (width rectang)
      (let ((seg (car x)))
        (let ((s (start-segment seg))
              (e (end-segment seg)))
          (sqrt (+ (square (- (x-point s)
                              (x-point e)))
                   (square (- (y-point s)
                              (y-point e))))))))

    square過程就是平方過程,假設已經定義。
    感冒發燒,頭痛欲裂,又下雨,心情有點郁悶。
    繼續:
    習題2.4,利用代換模型,很明顯過程cons返回一個過程作為結果,這個過程以m做參數,而在car的定義中,將這個返回的過程作用于另一個過程(lambda(p q) p),顯然m就是過程(lambda(p q) p) ,作用于參數x、y,返回x,因此cdr的定義應該為:
    (define (cdr z)
      (z (
    lambda (p q) q)))

    習題2.5, 利用上一章已經實現的expt求冪過程expt:
    (define (cons a b) (* (expt 2 a) (expt 3 b)))

    求a、b,需要反過來求指數,先設計一個求指數的過程:
    (define (get-n x p n)
      (
    if (> (remainder x p) 0)
          n
          (fact
    -n (/ x p) p (+ n 1))))

    因此car、cdr可以寫為:

    (define (car z) (get
    -n z 2 0))
    (define (cdr z) (get
    -n z 3 0))

    習題2.6就是注明的丘奇數(Church數),通過代換原則可以得到one:
    ;; 代換得到1
    ;; one 
    = add-1 zero
    ;;     
    = (lambda (f) (lambda (x) (f ((zero f) x))))
    ;;     
    = (lambda (f) (lambda (x) (f x)))

    (define one (lambda (f) (lambda (x) (f x))))

    ;; 代換得到2
    ;; 同理 two 
    = add-1 one 可得
    (define two (lambda (f) (lambda (x) (f (f x)))))

    ;; 因此
    +運算定義為
    (define (add a b)
      (lambda (f) (lambda (x) ((b f) ((a f) x)))))
    關于丘奇數推薦一篇文章:lambda算子3:阿隆佐。丘奇的天才,一個系列介紹lambda算子理論的文章,非常棒。

    習題2.7到習題2.16都是關于一個區間數據抽象的習題系列。
    先看習題2.7,很明顯:
    (define (make-interval a b) (cons a b))
    (define (lower
    -bound x) (car x))
    (define (upper
    -bound x) (cdr x))

    習題2.8.類似于除法,減法應該是第一個區間加上第2個區間的相反數,一個區間的相反數的兩個限界應該是原來區間的下界的相反數和上界的相反數,因此減法定義為:
    (define (sub-interval x y)
      (add
    -interval x (make-interval (- 0 (lower-bound y)) (- 0 (upper-bound y)))))

    完整是區間抽象定義如下:
    (define (make-interval a b) (cons a b))
    (define (lower
    -bound x) (car x))
    (define (upper
    -bound x) (cdr x))
    (define (add
    -interval x y)
      (make
    -interval (+ (lower-bound x) (lower-bound y))
                     (
    + (upper-bound x) (upper-bound y))))
    (define (mul
    -interval x y)
      (let ((p1 (
    * (lower-bound x) (lower-bound y)))
            (p2 (
    * (lower-bound x) (upper-bound y)))
            (p3 (
    * (upper-bound x) (lower-bound y)))
            (p4 (
    * (upper-bound x) (upper-bound y))))
        (make
    -interval (min p1 p2 p3 p4)
                       (max p1 p2 p3 p4))))
    (define (div
    -interval x y)
      (mul
    -interval x (make-interval (/ 1.0 (upper-bound y)) (/ 1.0 (lower-bound y)))))
    (define (
    sub-interval x y)
      (add
    -interval x (make-interval (- 0 (lower-bound y)) (- 0 (upper-bound y)))))

    習題2.9,首先定義下區間的寬度:
    (define (width-interval x)
      (
    / (- (upper-bound x) (lower-bound x)) 2.0))
    要證明區間加減算術的結果的寬度等于兩個運算數的寬度的加減結果很簡單,區間加減運算都是區間的上界與上界、下界與下界進行加減運算,而寬度
    width1=(b1-a1)/2
    width2=(b2-a2)/2
    減法:
    sub-width=((b2-b1)-(a2-a1))/2=((b2-a2)-(b1-a1))/2=width1-width2
    同樣加法:
    add-width=((b2+b1)-(a2+a1))/2=((b2-a2)+(b1-a1))/2=width1+width2

    舉例說明乘除不是這樣的結果:
    > (define x (make-interval 0 10))
    > (define y (make-interval 1 8))
    > (width-interval x)
    5.0
    > (width-interval y)
    3.5
    > (define add-result (add-interval x y))
    > (width-interval add-result)
    8.5
    > (define sub-result (sub-interval x y))
    > (width-interval sub-result)
    1.5
    > (define mul-result (mul-interval x y))
    > (width-interval mul-result)
    40.0
    > (define div-result (div-interval x y))
    > (width-interval div-result)
    5.0

    習題2.10,為什么被除的區間不能橫跨0呢?顯然,如果區間橫跨0,那么肯定是下界是負數,而上界>=0,因此上界的倒數仍然是大于下界的倒數,無法將上界的倒數作為下界,這與除法的定義產生沖突。因此修改除法運算檢測這種情況:
    (define (div-interval x y)
      (
    if (< (* (lower-bound y) (upper-bound y)) 0) (display "被除區間不能橫跨0")
      (mul
    -interval x (make-interval (/ 1.0 (upper-bound y)) (/ 1.0 (lower-bound y))))))

    習題2.11,一個區間的端點可能有3種情況:兩端同為正,同為負,一負一正。兩個區間相乘那么就有3*3=9種情況了,分析下這9種情況就可以得到:
    (define (mul-interval x y)
      (let ((l
    -x (lower-bound x))
            (u
    -x (upper-bound x))
            (l
    -y (lower-bound y))
            (u
    -y (upper-bound y)))
        (cond ((
    > l-x 0) (cond ((> l-0) (make-interval (* l-x l-y) (* u-x u-y)))
                               ((
    < u-0) (make-interval (* u-x l-y) (* l-x u-y)))
                               (
    else (make-interval (* u-x l-y) (* u-x u-y)))))
              ((
    < u-x 0) (cond ((> l-0) (make-interval (* l-x u-y) (* u-x l-y)))
                               ((
    < u-0) (make-interval (* u-x u-y) (* l-x l-y)))
                               (
    else (make-interval (* l-x u-y) (* l-x l-y)))))
              (
    else      (cond ((> l-0) (make-interval (* l-x u-y) (* u-x u-y)))
                               ((
    < u-0) (make-interval (* u-x l-y) (* l-x l-y)))
                               (
    else (make-interval
                                      (min (
    * l-x u-y) (* l-y u-x))
                                      (max (
    * l-x l-y) (* u-x u-y)))))))))

    習題2.12解答:
    (define (make-center-percent c p)
      (
    if (or (< p 0) (> p 1))
          (error 
    "百分比必須在0和1之間")
          (let ((a (
    * c (+ 1.0 p)))
                (b (
    * c (- 1.0 p))))
            (cons
    (min a b) (max a b)))))

    (define (center i)
      (
    / (+ (car i) (cdr i)) 2.0))

    (define (percent i)
      (let ((l (car
    i))
            (r (cdr
    i)))
        (
    / (- r l) (abs (+ r l)))))

    習題2.13,假設第一個區間為(make-center-percent c1 p1),第二個區間為(make-center-percent c2 p2),并且都為正數,那么兩個區間的成乘積的百分比計算公式為:
    c1c2(1+p1)(1+p2)-c1c2(1-p1)(1-p2)
    ----------------------------------
    c1c2(1+p1)(1+p2)+c1c2(1-p1)(1-p2)
    簡化這個分式為:
    p1+p2
    -----
    1+p1p2
    因為p1,p2都是很小的百分比,那么p1*p2的值可以接近于0,因此乘積的百分比近似公式就是p1+p2,也就是兩個相乘區間的百分比之和。





    posted @ 2007-05-23 11:57 dennis 閱讀(1088) | 評論 (0)編輯 收藏

        讀的是wl95421的《wicket開發指南-簡體中文版》,我之前沒有接觸過Tapestry,據說wicket借鑒了很多Tapestry的特性并做了相當的簡化。上手幾個demo后,感覺跟C/S的開發有點像,特別是類似delphi的組件型開發方式。一個頁面有一個Page和markup組成,Page繼承WebPage負責頁面的輸出,而markup文件描述界面,真正做到了html頁面與java代碼的分離,對網頁編輯工具友好。wicket是通過在html中添加id來實現分離,比如:
    <label wicket:id="name">這里輸出名字</label>

    在Page中添加要輸出的文字:
    this.add(new Label("name","dennis zane"));

        wicket與swing的設計理念一致,遵循MVC模式,Model用于提供數據,View是普通的html文件(markup文件),Controller是一個一個Page類。wicket同樣提供了很多的控件,這樣的開發方式非常類似ASP.net或者JSF,特別是一些高級控件的功能很強悍,比如Tree、TreeTable、GridView等等。感覺這個框架適合做快速開發,適用于中小型項目,因為此類項目的UI改動頻率比較大,同時代碼的侵入性太大。其他沒什么好談的,關于具體的開發請參考文檔了,比較少見的是與spring的集成,有一個wicket-spring的擴展包可以實現將spring容器管理的bean注入wicket的Page中,比如UserPage調用UserService:
             @SpringBean
            
    private UserService service;
    采用annotation標注。最后給個例子吧,整數的四則運算,首先看markup:
    <html>
    <title>加法計算</title>
    <body>
    <center>
    <span wicket:id ="feedback">這里用來輸出信息</span>
    <form wicket:id="form">
      
    <input type="text" size='10' wicket:id="a"/>&nbsp;<select wicket:id="oper"></select>&nbsp; <input type="text" size='10' wicket:id="b"/>&nbsp;=&nbsp;<label wicket:id="result"></label>
      
    <br><wicket:id ="sumit">add</a>
    </form>
    </center>
    </body>
    </html>

    一個feedback控件用于返回提示消息,兩個text控件用于輸入,一個下拉框用于選擇運算符,另外一個標簽顯示結果了,普通的html代碼,沒有什么好解釋的。再看TestPage.java:
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;

    import wicket.Component;
    import wicket.markup.html.WebPage;
    import wicket.markup.html.basic.Label;
    import wicket.markup.html.form.DropDownChoice;
    import wicket.markup.html.form.Form;
    import wicket.markup.html.form.SubmitLink;
    import wicket.markup.html.form.TextField;
    import wicket.markup.html.panel.FeedbackPanel;
    import wicket.model.Model;

    public class TestPage extends WebPage {

        
    private static List opers = new ArrayList();
        
    static {
            opers.add(
    "+");
            opers.add(
    "*");
            opers.add(
    "-");
            opers.add(
    "/");
        }

        
    private String oper = "+";

        
    private double result = 0;

        
    private double a = 0, b = 0;

        
    public TestPage () {
            
    super();
            add(
    new FeedbackPanel("feedback"));
            TextField ta 
    = new TextField("a"new Model() {
                
    public void setObject(Serializable obj) {
                    a 
    = ((Double) obj).doubleValue();
                }
            }, Double.
    class);
            TextField tb 
    = new TextField("b"new Model() {
                
    public void setObject(Serializable obj) {
                    b 
    = ((Double) obj).doubleValue();
                }
            }, Double.
    class);
            Form form 
    = new Form("form") {
                
    protected void onSubmit() {
                    
    switch (oper.toCharArray()[0]) {
                    
    case '+':
                        result 
    = a + b;
                        
    break;
                    
    case '-':
                        result 
    = a - b;
                        
    break;
                    
    case '*':
                        result 
    = a * b;
                        
    break;
                    
    case '/':
                        result 
    = a / b;
                        
    break;
                    
    default:
                        result 
    = a + b;
                    }
                }
            };
            add(form);

            form.add(ta);
            form.add(tb);
            Label label 
    = new Label("result"new Model() {
                
    public Object getObject(Component component) {
                    
    return String.valueOf(result);
                }
            });
            form.add(label);
            form.add(
    new SubmitLink("sumit"));
            DropDownChoice dropDownChoice 
    = new DropDownChoice("oper"new Model() {
                
    public void setObject(Serializable obj) {
                    oper 
    = (String) obj;
                }
            }, opers);
            dropDownChoice.setRequired(
    true);
            dropDownChoice.setNullValid(
    true);
            form.add(dropDownChoice);
        }
    }

    通過add方法添加控件,值的注意的就是怎么把控件跟Model聯系起來,這只是個小例子,直接重寫Model的setObject方法即可,將控件的值設置到變量以便計算。另外wicket的Page是線程安全的。

    posted @ 2007-05-22 16:16 dennis 閱讀(2523) | 評論 (1)編輯 收藏

        第一章兩天前就讀完了,因為工作上的事情拖到現在才來做最后這七道題,這些題目都是要求寫一個過程返回另一個過程作為結果。

    習題1.40,顯而易見,要求cubic過程返回的就是方程本身,照著定義來就行了:
    (define (cubic a b c)
      (lambda(x) (
    + (* x x x) (* a x x) (* b x) c)))

    習題1.41,注意到了題目已經說明了:以有一個參數的過程做參數,那就很簡單了:
    (define (double g) (lambda(x) (g (g x))))

    返回lambda構造的過程,參數過程應用兩次即可,那么
    > (((double (double double)) inc) 5)
    21

    習題1.42,組合應用:
    (define (composite f g)
      (lambda(x) (f (g x))))

    習題1.43,在1.42基礎上使用遞歸即可:
    (define (repeated f n)
      (
    if (= n 1)
          f
          (composite f (repeated f (
    - n 1)))))

    習題1.44,在1.43基礎上,首先定義smooth過程:
    (define (smooth f)
      (lambda(x) (
    / (+ (f (- x dx)) (f x) (f (+ x dx))) 3)))

    然后使用repeated過程產生n次平滑函數:
    (define (repeate-smooth n)
      (repeated smooth n))

    習題1.45,不是一下子能說清楚,經過測試可以知道n次方根搜索不動點,平均阻尼需要經過log2(n)(以2為底的對數)重復才會收斂,因此:
    (define (nth-root-test x n k)
      (fixed
    -point ((repeated average-damp k) (lambda (y) (/ x (fast-expt y (- n 1)))))
                   
    1.0))

    習題1.46,這題很有趣,產生過程的過程也是遞歸的,相當好玩,iterative-improve產生的過程需要遞歸調用自身,仍然使用iterative-improve產生:
    (define (iterative-improve good-enough improve-it)
      (lambda(guess) 
        (
    if (good-enough guess)
            guess
            ((iterative
    -improve good-enough improve-it) (improve-it guess)))))
    如果猜測結果足夠,返回猜測結果,如果沒有,遞歸調用lambda產生的這個過程應用于改進后的猜測值。
    重寫sqrt如下:

    (define (sqrtt x)
      (define (good
    -enough? guess)
          (
    < (abs (- (square guess) x)) 0.0001))
      (define (improve guess)
        (average guess (
    / x guess)))
      (iterative
    -improve good-enough? improve))
    注意,這里的sqrrt過程產生的是一個以初始猜測值為參數的過程,所有調用應該這樣:
    > ((sqrtt 41.0)
    2.000000000929222947

    下面的fixed-point過程也是如此。


    重寫fixed-point過程如下:
    (define (fixed-point f)
      (define tolerance 
    0.00001)
      (define (good
    -enough? guess)
        (
    < (abs (- guess (f guess))) tolerance))
      (define (improve guess) (f guess))
      (iterative
    -improve good-enough? improve))




    posted @ 2007-05-18 15:58 dennis 閱讀(768) | 評論 (0)編輯 收藏

        JavaOne放出來的新東西,出來也有段時間了,看了論壇和blog上的討論,叫好、不看好的各占一半。今天就去https://openjfx.dev.java.net/ 下載了netbean插件,按照getting startted做了一些例子。總體來說,JavaFx仍然是在awt/swing的基礎上的包裝,只不過用一層薄薄的性感語法包裝了一把,而且這語法與javascript等腳本語言基本一致,特別是聲明性的編程語法與json非常相似。據sun聲稱要退出一個消費者版本的jre,大概5M-9M大小,消息參見《桌面java的缺陷:面向消費者的jre》,這個恐怕也是給JavaFx專門定制的吧。個人觀點:沒有什么令人激動的新鮮玩意,特別是布局方面仍然是麻煩的layout機制,對多媒體的支持還是比不上flash,優點在于與java服務端通信方面(因為都是java平臺)可能比較有優勢,另外就是消費者版本jre的推出是個好消息,jre實在太大了。

        說了這么多,看看Hello World怎么寫的,實在與json太相似了:
    import javafx.ui.*;
    Frame {
         title: 
    "Hello World JavaFX"
         width: 
    200
         height: 
    200
         content: Label {
          text: 
    "Hello World"
         }
         visible: 
    true
    }

        這是聲明方式來創建一個Frame,Frame里面放個Label,Label上一句Hello World。也可以采用編程方式:
            var win = new Frame();
            win.title 
    = "Hello World JavaFX";
            win.width 
    = 200;
            
    var label = new Label();
            label.text 
    = "Hello World";
            win.content 
    = label;
            win.visible 
    = true;

    這語法與javascript有什么不同呢?
        再來看看事件處理,仍然遵循MVC模式,比如我們希望輸入框的文字修改能同時修改窗體的title,首先定義一個Model:
           class HelloWorldModel {
                attribute saying: String;
            }

            var model 
    = HelloWorldModel {
                saying: 
    "Hello World"
            };

        把Model綁定到View上:
       
            var win = Frame {
                title: bind 
    "{model.saying} JavaFX"
                width: 
    200
                content: TextField {
                    value: bind model.saying
                }
                visible: 
    true
            };

    TextFiled的value與model的saying操作進行了綁定,而Frame的title也綁定了model的saying方法,因此輸入框的文字改變的話,也會反映到title上咯。"{model.saying} JavaFX"倒是類似ruby對字符串的處理方法了。這些例子代碼完全來自 Getting Started With JavaFx script language,更多精彩內容請自己解讀。題外話:netbean蠻好用的啊,在我的1G內存機器上跑的挺歡。

    posted @ 2007-05-18 11:05 dennis 閱讀(22456) | 評論 (14)編輯 收藏

        搞定了工作,繼續做習題:)
        題1.37:無窮連分式的過程描述,我發現這道題用迭代比遞歸反而更容易寫出來,遞歸不是那么顯而易見。
    遞歸版本:
    (define (cont-frace n d k)
      (
    if (= k 1)
          (
    / (n 1) (d 1))
          (
    / (n k) (+ (d k) (cont-frace n d (- k 1))))))

    再看迭代版本:
    (define (cont-frace-iter n d result counter k)
      (
    if (= counter 0)
          result
          (cont
    -frace-iter n d (/ (n counter) (+ (d counter) result)) (- counter 1) k)))
    (define (cont
    -frace n d k)
      (cont
    -frace-iter n d 0 k k))

    當n d的過程都是(lambda (x) 1.0)時,趨近于1/φ(黃金分割比的倒數),通過計算可得知,當k>=11時,滿足十進制的4位精度。

       題1.38在1.37的基礎上,關鍵在于寫出d過程,通過觀察給出的序列可以發現,當i-2是3的倍數時,(d i)應該返回2(i+1)/3,由此先寫出d過程:
    (define (d i)
      (cond ((
    = i 11)
            ((
    = i 22)
            ((
    = (remainder (- i 230) (/ (* 2 (+ i 1)) 3))
            (
    else
               
    1)))
     
       據此求出e:
    (+ 2 (cont-frace (lambda(i) 1.0) d 1000))


    posted @ 2007-05-17 11:34 dennis 閱讀(724) | 評論 (0)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 39 40 41 42 43 44 45 46 47 下一頁 Last 
    主站蜘蛛池模板: 亚洲国产精品无码久久九九大片 | 中文字幕手机在线免费看电影 | 最新久久免费视频| 亚洲一区二区三区成人网站| 国产亚洲一区二区精品| 国产精品免费视频一区| 亚洲人成免费电影| 日本一区午夜艳熟免费| 人妻仑乱A级毛片免费看| 亚洲熟女综合一区二区三区| 中文字幕亚洲色图| 亚洲色爱图小说专区| 免费成人av电影| 国产男女猛烈无遮挡免费视频网站| 每天更新的免费av片在线观看| 国内精品免费久久影院| 国产青草亚洲香蕉精品久久| 亚洲中文字幕精品久久| 亚洲无人区视频大全| 亚洲日本中文字幕| 亚洲国产三级在线观看| 亚洲国产一区二区三区| 免费看一级做a爰片久久| 色视频色露露永久免费观看| 999久久久免费精品国产| 国产人成免费视频网站| h视频在线观看免费完整版| 色欲A∨无码蜜臀AV免费播| 国产午夜无码精品免费看动漫| 两性色午夜视频免费播放| 一级特黄aaa大片免费看| 成人在线免费视频| EEUSS影院WWW在线观看免费| 人妻仑刮八A级毛片免费看| 窝窝影视午夜看片免费| 黄色三级三级三级免费看| 永久免费无码日韩视频| 黄色片网站在线免费观看| 一区二区三区免费视频观看| 国产精品hd免费观看| 国产婷婷成人久久Av免费高清 |