posts - 189,comments - 115,trackbacks - 0
          Java基礎(chǔ)知識部分總結(jié)

          本文就java基礎(chǔ)部分容易混淆的一些知識點進行了一下總結(jié)。因為Java本身知識點非常多,不可能在很短的篇幅就能敘述完,而且就某一個點來講,如欲仔細(xì)去探究,也能闡述的非常多。這里不做全面仔細(xì)的論述,僅做為一個引子,拋磚引玉。具體個例,還需各位看官自己驗證一下,以增進理解和記憶。
          ??
          ??歡迎就這一部分各位朋友與我進行探討,共同進步。
          1、雖然有很多朋友可能進行了多年的java開發(fā)老手,但可能仍舊對某些點缺乏仔細(xì)探究。
          2、去一些公司求職面試或筆試時的技術(shù)題目中,也往往會涉及到這里的一些內(nèi)容。
          ??所以,希望下邊的這些總結(jié)能夠?qū)σ恍W(xué)習(xí)java或求職的朋友有些許幫助。


           ???
           ?1、?關(guān)于java類中的缺省的構(gòu)造器
          如果一個java類沒有顯式定義沒有參數(shù)的構(gòu)造器,將有一個默認(rèn)缺省的構(gòu)造器。如果定義了一個有參數(shù)的構(gòu)造器,那么原來的缺省的構(gòu)造器將不在有效。
          public?class?A{?
          }
          此時如果用?new?A();?java編譯器將使用缺省的構(gòu)造器。
          public?class?A{?
          public?A(int?i){?
          }
          }
          如果此時用?new?A();?將產(chǎn)生一個編譯錯誤,因為此時顯式定義了,一個有參數(shù)的構(gòu)造器。


          2、Java中的類名與文件名
          1、在一個java文件中可以有多于一個類定義(更常見于某些組件的監(jiān)聽器類),但只能有一個public?class定義,且與文件同名。
          2、如果一個java源文件中沒有public類,那么每個類的名字沒特殊規(guī)則,即不必與文件同名。
          3、在編譯后產(chǎn)生的class文件中,仍舊是多個單獨分開的class文件。


          3、import關(guān)鍵字
          1、import語句必須定義在所有的class定義之前。
          2、import語句只是為編譯器指明了一個路徑,并不像C或C++中的#include,所以用import?.*并不影響性能


          4、Java中的幾個特殊關(guān)鍵字
          Java中的關(guān)鍵字許多大家都比較熟悉,而有幾個就不是很常用,如:
          1、goto和const是保留關(guān)鍵字,在java中沒使用
          2、strictfp和volatile不常用;?sizeof、zhen不是關(guān)鍵字。
          3、true,false,null不是嚴(yán)格意義上的關(guān)鍵字,而是literals。

          ??
          5、java方法中的傳遞值參
          在Java方法中傳遞參數(shù),對于基本類型來講傳遞的是值參數(shù),相當(dāng)于建立的一個參數(shù)的拷貝,不影響原來變量的值。
          在引用方法中可以改變傳遞對象的內(nèi)容,但對象引用(像A@5d87b2)從來不會改變。

          public?class?tt{?
          public?static?void?main?(String?args[]){
          ??A?aa?=?new?A();
          ??aa.num?=5;
          ??tt?t?=?new?tt();
          ??System.out.println("11?aa="+aa?+?"num="+aa.num);
          ??t.test(aa);
          ??System.out.println("22?aa="+aa?+?"num="+aa.num);
          }?
          void?test(A?a){
          ??A?ab?=?new?A();
          ??a?=?ab;
          ??System.out.println("33?ab="+ab?+?"num="+ab.num);
          }?
          }
          class?A{?
          int?num;
          }?
          ??
          6、變量初始化
          java中的變量在使用之前必須被初始化,當(dāng)創(chuàng)建一個對象的時候一些類的變量會自動初始化并賦予缺省值。
          數(shù)字類賦值0;char類型賦值'\u0000';?boolean類型賦值false;引用對象賦值null;
          注意的是在方法之外的類變量的值是自動賦初始值,而方法內(nèi)的局部變量必須手工初始化。?

          class?AA{?
          int?num;?
          void?test(){
          ??int?j;
          ??j?=5;//沒有這一行則編譯不會通過。
          ??j?=?j+num;
          }
          }?
          ??
          7、switch語句
          這個點經(jīng)常在求職筆試題目中出現(xiàn)。default放在最上邊編譯沒問題;碰到符合分支的,如果沒有break會一直向下運行。?

          public?class?tt{?
          public?static?void?main?(String?args[]){?
          ??tt?t?=?new?tt();?
          ??t.test(2);//可改變成3運行一下看一下結(jié)果?
          }?
          void?test(int?i){
          ??switch?(i){
          ????default:?
          ????System.out.println("default");?
          ????case?1:?
          ????System.out.println("111");
          ????break;
          ????case?2:
          ????System.out.println("222");
          ????break;?
          ??}
          }?
          }?
          ??
          8、關(guān)于java中的label使用
          ??break?[label]
          ??continue[lbele]
          ??lable:?statement;?//這里的statement必須是一個loop循環(huán)
          public?class?tt{?
          public?static?void?main?(String?args[]){?
          ??tt?t?=?new?tt();
          ??t.test();?
          }
          void?test(){?
          ??System.out.println("0000");
          ??lb1:for?(int?i=0;i<10;i++){
          ????lb2:for?(int?j=0;?j<2;?j++){
          ??????if?(i==2)?continue?lb1;
          ??????System.out.println("i="+i?+"?j="+j);?
          ????}?
          ??}
          ??System.out.println("111111");?
          }?
          }?
          ??
          9、類型轉(zhuǎn)換校正
          class?Employee
          ??????|
          class?Manager
          向上校正,總是允許的,Manager直接使用父類Employee的方法。
          向下校正,必須用instanceof檢驗,才能將一個Employee轉(zhuǎn)換為Manager對象。

          public?void?test(Employee?e){
          if?(e?instanceof?Manager){
          ??Manager?m?=?(Mnager)e;
          ??...
          }
          }?
          ??
          10、方法重載(overloading)、方法覆蓋(overriding)

          方法重載(overloading)一定要求名字相同,參數(shù)不同,返回類型可以相同也可以不同

          class?A{?
          void?test(int?i){?
          }
          }
          class?AA?extends?A{
          int?test(int?i,?int?j){
          ??return?5;?
          }?
          }?
          注:方法覆蓋(overriding)要求名字,參數(shù),返回類型全部必須相同,訪問控制符可以不同,但必須大過父類的。因為如果名字和參數(shù)都已經(jīng)相同了則一定要求返回類型相同,否則認(rèn)為這是一個新的方法了,名字就必須不同了。

          class?A{?
          void?test(int?i){?
          }
          }
          class?AA?extends?A{
          public?void?test(int?i){//若是換成private則編譯不通過。?
          }?
          }

          注:關(guān)于覆蓋方法拋出異常的問題。如A是父類,B是繼承A的子類。B中的方法meth()去覆蓋父類A的此方法時,B中不能throws出新的異常,只能是父類拋出的異常或其子集。更甚至可以不拋出異常。?

          ??
          11、關(guān)于類的構(gòu)造器重載問題

          class?A{
          public?A(int?i){
          }?
          }
          class?AA?extends?A{
          public?AA(){
          ??int?i?=?5;?//?這里出錯,沒有父構(gòu)造器?
          }
          }?
          由于父類A自定義了構(gòu)造器,所以缺省的構(gòu)造器就丟失了,當(dāng)子類的構(gòu)造器自動試圖調(diào)用父類沒參數(shù)的構(gòu)造器時卻沒有,所以會編譯出錯。?

          ??
          12、關(guān)于static關(guān)鍵字總結(jié):
          1、不能在static修飾的方法中引用this變量,只能引用一些靜態(tài)變量或方法,或new新的對象(可以定義局部變量)。
          簡言之,靜態(tài)方法或塊中,只能引用靜態(tài)的方法或變量。
          2、類中的成員變量(static修飾)有缺省值,而類的定義的方法中的局部變量沒有缺省值。
          3、在類的構(gòu)造器中,可以引用任何的靜態(tài)或非靜態(tài)的變量和方法,可以在非static方法中調(diào)用static方法。
          4、static{}塊中的代碼在類裝載中僅執(zhí)行一次。
          5、在7-7,A?static?method?cannot?be?overridden?but?can?be?hidden.?不理解。
          6、不能在無論非static方法中或static方法中定義static變量。?

          ??
          13、關(guān)于final關(guān)鍵字
          1、不能繼承final修飾的類,不能覆蓋final修飾的方法。
          2、final修飾的變量,若沒賦值,必須在構(gòu)造器中賦初始值。

          class?A{
          final?int?j;
          public?A(){?
          ??j?=?9;//若沒有此行,則編譯不通過。?
          }?
          }
          3、final類型的方法參數(shù)可定義,但不能改變。
          class?A{
          void?m(final?int?i){?//這一行的聲明i為一個final沒問題。
          ??i?++?;?//但在這里面,i的值不能再被改變。?
          }
          }?

          ??
          14、Interface接口關(guān)鍵字
          1、接口中的變量
          ??1、必須初始化其值。
          ??2、默認(rèn)修飾符為public+static+final,其他的修飾符不允許。
          2、接口中的方法
          ??1、默認(rèn)為public+abstract
          ??2、其它修飾符?static,private,protected,final,synchronized,native均不能有。

          interface?A{
          void?s();
          }
          class?AA?implements?A{
          void?s(){?//編譯器在這里提示由于接口中的方法s()修飾符默認(rèn)是public,
          ????????//而這里的s()默認(rèn)是protected,小于public所以不允許。
          }
          }?

          ??
          15、abstract抽象關(guān)鍵字
          abstract?class?A{
          private?int?i;?
          private?void?m();{}
          }?
          抽象類中可以有私有的變量和私有屬性,而接口就不行(原因如上),
          這是因為java是按實例虛擬調(diào)用的,在生成某一個具體的對象可以有私有的屬性或方法的。

          abstract?class?A{
          private?int?i;?
          private?void?m(){};
          public?abstract?void?n();//若是private則編譯不通過。
          }
          抽象類中的抽象方法是讓其他類繼承的,如果本身都是私有的,就沒有什么意義了?

          ??
          16、集合類型
          以有無順序,允許不允許重復(fù)區(qū)分
          Collections:?一組對象,無序集合,允許重復(fù)
          Set:無序集合,不允許重復(fù)
          List:有序集合,允許重復(fù)
          注意:在JDK1.1中定義的集合類型,都是線程安全的,所以都是“重量級”的。像HashTable,Vector
          而在java2中定義的一些新的集合類型如HashMap,?ArrayList不是線程安全的,是“輕量級”的,但速度快,性能好。這一點在許多公司面試試題都見過。?

          ??
          17、布局管理器
          FlowLayout,BorderLayout,GridLayout,CardLayout
          關(guān)于Panel和Frame默認(rèn)的Layout常在一些公司的面試試題中出現(xiàn)。
          1、Panel和Applet類默認(rèn)的布局管理器是FlowLayout?一個一個的加上去
          2、Frame和window類默認(rèn)的布局管理器是BorderLayout?按東南西北加入
          3、xyLayout是Borland公司開發(fā)的布局管理器。?

          ??
          18、面試試題中Applet部分
          1、使用代碼
          ??<applet?code?=?"a.class"?width=100?height=200>
          ????<param?name=a?vlaue"11">
          ??</applet>
          2、可以覆蓋的方法init(),start(),stop(),destory(),paint(g)?

          ??
          19、面試試題中線程部分
          1、基本實現(xiàn)方式兩中,繼承Thread類和實現(xiàn)Runnable接口
          2、必須實現(xiàn)父類或接口中的run()方法。
          3、有關(guān)線程方法,start()啟動線程。
          ??join()指在調(diào)用這個線程的方法或進程中,必須等待此線程運行結(jié)束才能繼續(xù)其他進程。
          4、線程中的同步synchronized,注意死鎖。?

          ??
          20、對象串行化
          1、僅僅對象類型的數(shù)據(jù)可以串行化。
          2、標(biāo)記為transient的數(shù)據(jù)不可以串行化。
          存儲一個對象到某種永久性存儲叫persistence,如存儲到磁盤、磁帶或別的機器的內(nèi)存中。
          java.io.Serializable接口沒有定義方法要實現(xiàn),僅僅是一個標(biāo)記暗示實現(xiàn)了這個接口的類可以被考慮串行化。沒有實現(xiàn)這個接口的對象不能保存或存儲它們的狀態(tài)。
          當(dāng)一個對象被串行化的時候,僅僅數(shù)據(jù)被保留,而方法和構(gòu)造器不是串行化的部分。
          一些對象類是不能串行化的因為他們代表的數(shù)據(jù)是經(jīng)常變化的。如java.io.FileInputSream和java.langThread。如果串行化的對象包含了不可串行化的對象,整個串行化動作會失敗,并拋出NotSerializableException。?

          ??
          21、java中的網(wǎng)絡(luò)通訊

          一般的TCP/IP網(wǎng)絡(luò)數(shù)據(jù)通信主要可分2種,TCP和UDP

          TCP:TCP是面向連接的通信協(xié)議,就像打電話,先要撥通建立連接,傳送的數(shù)據(jù)不會丟失。
          ??java提供了ServerSocket和socket類。在server端,建立一個serverSocket,并指定端口,并偵聽連接。

          服務(wù)器端代碼?
          ServerSocket?sc=new?ServerSocket(1111);
          Socket?socket1=?sc.accept();
          DataInputStream?s_in?=?new?DataInputStream(socket1.getInputStream());

          客戶端代碼?
          Socket?socket2?=?new?Socket("192.168.1.1",1111);?


          UDP:UDP非面向連接,就像寫信,將傳輸?shù)臄?shù)據(jù)包成一個分組,可能有數(shù)據(jù)丟失

          服務(wù)器端代碼
          DatagramSocket?server?=?new?DatagramSocket(1234);
          DatagramPacket?in_packet?=new?DatagramPacket(in_buf,2000);
          server.recieve(in_packet);

          客戶端代碼
          DatagramSocket?client=?new?DatagramSocket(1235);
          DatagramPacket?out_packet=?
          ????????????new?DatagramPacket?(out_buf,100,"192.168.1.1",1234);
          client.send(outPacket);

          ??
          22、String對象
          一般講來創(chuàng)建的兩個對象如果用==來比較肯定是不等的,因為他們的引用地址是不同的,而==是對于對象來講是比較對象地址的。但對于String對象來講是一個例外,兩個String對象如果值相同,==比較也是相同的。我想這可能與Sun公司對String對象定義有關(guān)。

          public?class?tt{?
          public?static?void?main?(String?args[]){?
          ??tt?t?=?new?tt();?
          ??t.test(2);?
          }?
          void?test(int?i){
          ??String?s1?=?"123";
          ??String?s2?=?"123";
          ??if?(s1==s2)?
          ????System.out.println("111111");
          ??else
          ????System.out.println("2222222");
          }?
          }
          結(jié)果輸出:111111


          Java語言接口與繼承的本質(zhì)
          loveofgod 轉(zhuǎn)貼? (參與分:2027,專家分:345)?? 發(fā)表:2006-07-20 02:25 ??版本:1.0 ??閱讀:12

          計算機學(xué)院研二的兄弟與我討論Java,一見面,幾個問題全是關(guān)于接口,接口有什么用?為什么要用接口?什么時候該使用接口?很慶幸他們不是問我Java如何連接SQL?Server,或者是如何開發(fā)J2EE應(yīng)用,這類問題有殺傷力,避之則吉。今年計算機學(xué)院本科有個畢業(yè)設(shè)計課題是做J2ME,選這個題目的學(xué)生在5月末都還在苦著臉研究java.util.*這個包,這個這個……唉。?

            大多數(shù)人認(rèn)為,接口的意義在于頂替多重繼承。眾所周知Java沒有c++那樣多重繼承的機制,但是卻能夠?qū)嵶鞫鄠€接口。其實這樣做是很牽強的,接口和繼承是完全不同的東西,接口沒有能力代替多重繼承,也沒有這個義務(wù)。接口的作用,一言以蔽之,就是標(biāo)志類的類別(type?of?class)。把不同類型的類歸于不同的接口,可以更好的管理他們。OO的精髓,我以為,是對對象的抽象,最能體現(xiàn)這一點的就是接口。為什么我們討論設(shè)計模式都只針對具備了抽象能力的語言(比如c++、java、c#等),就是因為設(shè)計模式所研究的,實際上就是如何合理的去抽象。(cowboy的名言是“抽象就是抽去像的部分”,看似調(diào)侃,實乃至理)。?

            設(shè)計模式中最基礎(chǔ)的是工廠模式(Factory),在我最近的一個很簡單的應(yīng)用中,我想盡量的讓我的程序能夠在多個數(shù)據(jù)庫間移植,當(dāng)然,這涉及很多問題,單是如何兼容不同DBMS的SQL就讓人頭痛。我們不妨先把問題簡單化,只考慮如何連接不同的數(shù)據(jù)庫。?

            假設(shè)我有很多個類,分別是Mysql.java、SQLServer.java、Oracle.java、DB2.java,他們分別連接不同的數(shù)據(jù)庫,統(tǒng)一返回一個Connection對象,并且都有一個close方法,用于關(guān)閉連接。只需要針對你的DBMS,選擇不同的類,就可以用了,但是我的用戶他會使用什么數(shù)據(jù)庫?我不知道,我希望的是盡量少的修改代碼,就能滿足他的需要。我可以抽象如下接口:?

            package?org.bromon.test;?
            public?interface?DB?
            {?
            java.sql.Connection?openDB(String?url,String?user,String?password);?
            void?close();?
            }?

            這個接口只定義兩個方法,沒有任何有實際意義的代碼,具體的代碼由實作這個接口的類來給出,比如Mysql.java:?

            Package?org.bromon.test;?
            import?java.sql.*;?
            public?class?Mysql?implements?DB?
            {?
            private?String?url=”jdbc:mysql:localhost:3306/test”;?
            private?String?user=”root”;?
            private?String?password=””;?
            private?Connection?conn;?
            public?Connection?openDB(url,user,password)?
            {?
              //連接數(shù)據(jù)庫的代碼?
            }?

            public?void?close()?
            {?
              //關(guān)閉數(shù)據(jù)庫?
            }?
            }?

            類似的當(dāng)然還有Oracle.java等等,接口DB給這些類歸了個類,在應(yīng)用程序中我們這樣定義對象:?

            org.bromon.test.DB?myDB;?

            使用myDB來操作數(shù)據(jù)庫,就可以不用管實際上我所使用的是哪個類,這就是所謂的“開-閉”原則。但是問題在于接口是不能實例化的,myDB=new?DB(),這樣的代碼是絕對錯誤的,我們只能myDB=new?Mysql()或者myDB=new?Oracle()。麻煩了,我還是需要指定具體實例化的是哪個類,用了接口跟沒用一樣。所以我們需要一個工廠:?

            package?org.bromon.test;?
            public?class?DBFactory?
            {?
            public?static?DB?Connection?getConn()?
            {?
              Return(new?Mysql());?
            }?
            }?

            所以實例化的代碼變成:myDB=DBFactory.getConn();?

            這就是23種模式中最基礎(chǔ)的普通工廠(Factory),工廠類負(fù)責(zé)具體實例化哪個類,而其他的程序邏輯都是針對DB這個接口進行操作,這就是“針對接口編程”。責(zé)任都被推卸給工廠類了,當(dāng)然你也可以繼續(xù)定義工廠接口,繼續(xù)把責(zé)任上拋,這就演變成抽象工廠(Abstract?Factory)。?

            整個過程中接口不負(fù)責(zé)任何具體操作,其他的程序要連接數(shù)據(jù)庫的話,只需要構(gòu)造一個DB對象就OK,而不管工廠類如何變化。這就是接口的意義----抽象。?

            繼承的概念不用多說,很好理解。為什么要繼承呢?因為你想重用代碼?這絕對不是理由,繼承的意義也在于抽象,而不是代碼重用。如果對象A有一個run()方法,對象B也想有這個方法,所以有人就Class?B?extends?A。這是不經(jīng)大腦的做法。如果在B中實例化一個A,調(diào)用A的Run()方法,是不是可以達到同樣的目的?如下:?

            Class?B?
            {?
            A?a=new?A();?
            a.run();?
            }?

            這就是利用類的聚合來重用代碼,是委派模式的雛形,是GoF一貫倡導(dǎo)的做法。?

            那么繼承的意義何在?其實這是歷史原因造成的,最開始的OO語言只有繼承,沒有接口,所以只能以繼承來實現(xiàn)抽象,請一定注意,繼承的本意在于抽象,而非代碼重用(雖然繼承也有這個作用),這是很多Java爛書最嚴(yán)重的錯誤之一,它們所造成的陰影,我至今還沒有完全擺脫,壞書害人啊,尤其是入門類的,流毒太大。什么時候應(yīng)該使用繼承?只在抽象類中使用,其他情況下盡量不使用。抽象類也是不能實例化的,它僅僅提供一個模版而已,這就很能說明問題。?

            軟件開發(fā)的萬惡之源,一是重復(fù)代碼而不是重用代碼,二是爛用繼承,尤以c++程序員為甚。Java中取締多重繼承,目的就是制止?fàn)€用繼承,實是非常明智的做法,不過很多人都不理解。Java能夠更好的體現(xiàn)設(shè)計,這是讓我入迷的原因之一。

          XML和J2EE的完美結(jié)合
          loveofgod 轉(zhuǎn)貼? (參與分:2027,專家分:345)?? 發(fā)表:2006-07-19 17:15 ??版本:1.0 ??閱讀:15

          當(dāng)前,Java?2平臺企業(yè)版(J2EE)架構(gòu)在廠商市場和開發(fā)者社區(qū)中倍受推崇。作為一種工具,可擴展標(biāo)記語言(XML)簡化了數(shù)據(jù)交換、進程間消息交換這一類的事情,因而對開發(fā)者逐漸變得有吸引力,并開始流行起來。自然,在J2EE架構(gòu)中訪問或集成XML解決方案的想法也很誘人。因為這將是強大系統(tǒng)架構(gòu)同高度靈活的數(shù)據(jù)管理方案的結(jié)合。?

          XML的應(yīng)用似乎是無窮無盡的,但它們大致上可以分為三大類:?

          ●簡單數(shù)據(jù)的表示和交換(針對XML的簡單API(SAX)和文檔對象模型(DOM)語法解析,不同的文檔類型定義(DTDs)和概要(schemas))?

          ●面向消息的計算(XML-RPC(遠(yuǎn)程過程調(diào)用),SOAP協(xié)議,電子化業(yè)務(wù)XML(ebXML))?
          ●用戶界面相關(guān)、表示相關(guān)的上下文(可擴展樣式表語言(XSL),可擴展樣式表語言轉(zhuǎn)換(XSLT))?
          這幾類應(yīng)用在J2EE架構(gòu)中恰好有天然的對應(yīng):數(shù)據(jù)表示和交換功能是EJB組件模型中持久化服務(wù)(persistence?services)的一部分,基于消息的通訊由Java消息服務(wù)(JMS)API來處理,而界面表示正是Java服務(wù)器頁面(JSP)和Java?Servlets的拿手好戲。?
          在本文中,我們將看到當(dāng)今基于J2EE的應(yīng)用里,XML是如何在上述幾個方面進行應(yīng)用的,以及在相關(guān)標(biāo)準(zhǔn)的未來版本中這些應(yīng)用將會如何發(fā)展。?
          基礎(chǔ):數(shù)據(jù)的表示和交換?
          原型化的XML應(yīng)用(假設(shè)有的話)的內(nèi)容通常是:數(shù)據(jù)以XML格式存放,為了進行顯示、修改甚至寫入某個XML文檔而經(jīng)常被讀入到某個對象模型中。作為例子,假定我們正處理多種類型的媒體(圖品、視頻、文本文檔等等),并且用下面這個簡單的XML?DTD來描述這些媒體的元數(shù)據(jù):?
          <!--?DTD?for?a?hypothetical?media?management?system?-->?
          <!--?Media?assets?are?the?root?of?the?object?hierarchy.?Assets?are?also?
          hierarchical?-?they?can?contain?other?assets.?-->?
          <!ELEMENT?media-asset?(name,?desc?,?type*,?media-asset*,?urn)>?
          <!--?Metadata?about?the?asset?-->?
          <!ELEMENT?name?(#PCDATA)>?
          <!ELEMENT?desc?(#PCDATA)>?
          <!ELEMENT?type?(desc,?mime-type?)>?
          <!ELEMENT?mime-type?(#PCDATA)>?
          <!ELEMENT?urn?(#PCDATA)>?
            ???
          以下是一個基于上述媒體DTD的XML文檔,描述了與某個課程講座相關(guān)的內(nèi)容:?
          <?xml?version="1.0"??><!DOCTYPE?media-asset?PUBLIC?"-//Jim?Farley//DTD???
          Media?Assets//EN"?"http://localhost/Articles/Sun/dtds/media.dtd">?
          <media-asset>?
          <name>第14講</name>?
          <desc>與第14講相關(guān)的所有內(nèi)容</desc>?
          <!--?內(nèi)容對象"lecture?14"的一套子組件?-->???
          <media-asset>?
          <name>講座的幻燈片</name>?
          <type>?
          <desc>MS?PowerPoint</desc>?
          <mime-type>application/vnd.ms-powerpoint</mime-type>?
          </type>?
          <urn>http://javatraining.org/jaf/E123/lecture-?
          14/slides.ppt</urn>?
          </media-asset>?
          <media-asset>?
          <name>講座的視頻片斷</name>?
          <type>?
          <desc>RealPlayer?streaming?video</desc>?
          <mime-type>video/vnd.rn-realvideo</mime-type>?
          </type>?
          <urn>http://javatraining.org/jaf/E123/lecture-?
          14/lecture.rv</urn>?
          </media-asset>?
          <!--?講座開始?-->?
          <urn>http://javatraining.org/jaf/E123/lecture-14/index.jsp</urn>?
          </media-asset>???
          從Web或者企業(yè)級應(yīng)用的角度看,能以這種方式訪問數(shù)據(jù)真是一種福音,因為它體現(xiàn)了高度的可移動性,使我們與元數(shù)據(jù)的實際資源本身隔離。這些資源可能來自一個關(guān)系數(shù)據(jù)庫系統(tǒng)、某種活動媒體服務(wù)器或者Web服務(wù)器上的一個靜態(tài)XML文檔,等等。如果想把這些數(shù)據(jù)加載到Java應(yīng)用中,我們可以從當(dāng)前眾多的Java語言XML解析器中選用一個,通過它將XML數(shù)據(jù)裝入一個DOM文檔,最后遍歷文檔,將所有這些數(shù)據(jù)轉(zhuǎn)換到我們應(yīng)用系統(tǒng)的對象模型中。?
          下面是個簡單的基于DOM的解析程序,可對上述的媒體DTD進行解析。解析器用的是?
          Apache?Xerces:?
            ???
          package?jaf.xml;?
          import?java.util.*;?
          import?java.io.IOException;?
          import?org.w3c.dom.*;?
          import?org.xml.sax.*;?
            ???
          //?XML文檔解析程序,使用上述媒體DTD.?
          public?class?MediaParser?implements?ErrorHandler?{?
          /**?使用Apache?Xerces解析器?*/?
          org.apache.xerces.parsers.DOMParser?mParser?=???
          new?org.apache.xerces.parsers.DOMParser();?
          /**?構(gòu)造函數(shù)?*/?
          public?MediaParser()?{?
          //?告訴解析器驗證并解析文檔?
          try?{?
          mParser.setFeature(?"http://xml.org/sax/features/validation",???
          true);?
          }???
          catch?(SAXException?e)?{?
          System.out.println("Error?setting?validation?on?parser:");?
          e.printStackTrace();?
          }?
          //?設(shè)置解析器的錯誤處理句柄?
          mParser.setErrorHandler(this);?
          }?
          /**?解析指定的URL,返回找到的XML文檔?
          */?
          public?Document?parse(String?url)?throws?SAXException,?IOException?{?
          mParser.parse(url);?
          Document?mediaDoc?=?mParser.getDocument();?
          return?mediaDoc;?
          }?
          /**?解析指定URL的XML文檔,將內(nèi)容轉(zhuǎn)換成?MediaAsset?對象?
          */?
          public?Collection?loadAssets(String?url)?throws?SAXException,???
          IOException?{?
          Document?doc?=?parse(url);?
          Collection?assets?=?new?LinkedList();?
          NodeList?assetNodes?=?doc.getElementsByTagName("media-asset");?
          for?(int?i?=?0;?i?<?assetNodes.getLength();?i++)?{?
          Node?assetNode?=?assetNodes.item(i);?
          MediaAsset?asset?=?new?MediaAsset(assetNode);?
          assets.add(asset);?
          }?
          return?assets;?
          }?
          /**?
          *?錯誤處理代碼(為簡潔起見省略了)?
          */?
          }?
          MediaParser類的構(gòu)造函數(shù)初始化了一個Xerces?DOM解析器。parse()方法告訴解析器到哪個URL去找XML源,然后得到結(jié)果文檔并返回。loadAssets()方法調(diào)用parse()方法從某個XML源加載文檔,然后為文檔中找到的每個“media-asset”節(jié)點創(chuàng)建一個MediaAsset對象。?
          以下是一個使用MediaAsset類的例子:?
          package?jaf.xml;?
          import?java.util.*;?
          public?class?MediaAsset?{?
          //?資源元數(shù)據(jù)?
          private?String?mName?=?"";?
          private?String?mDesc?=?"";?
          private?Collection?mChildren?=?new?LinkedList();?
          private?Vector?mTypes?=?new?Vector();?
          private?String?mUrn?=?"";?
          protected?MediaAsset(org.w3c.dom.Node?assetNode)?{?
          //?為簡潔起見省略后面代碼?
          .?
          .?
          .?
          }?
          }?
          因為篇幅的關(guān)系省略了MediaAsset類的詳細(xì)代碼,但應(yīng)用模式依然是清晰的。MediaAsset類遍歷文檔的節(jié)點,當(dāng)它碰到不同的子節(jié)點時,它用子節(jié)點的內(nèi)容填充自己的成員數(shù)據(jù)。如果它發(fā)現(xiàn)了一個嵌套的子資源節(jié)點,它只需要創(chuàng)建一個新的MediaAsset對象,然后將子資源節(jié)點的數(shù)據(jù)填充到新對象的成員數(shù)據(jù)中。?
          實現(xiàn)上述處理的方法數(shù)不勝數(shù)。我們還可以使用其他的解析器或解析器架構(gòu),如Java?API?for?XML?Parsing?(JAXP)。除了使用DOM模型外,事件驅(qū)動的SAX模型也可用于解析XML。類似的程序也可用來產(chǎn)生XML數(shù)據(jù)??前提是允許產(chǎn)生新的數(shù)據(jù)對象(在本例中是MediaAsset),它可將其相應(yīng)的XML實體插入到DOM中,然后將DOM輸出到一個流中(諸如一個文件,一個Socket,或者一個HTTP連接...)。還有其他更高層次的標(biāo)準(zhǔn),可將XML映射到Java對象的過程進一步自動化(或簡化)。例如,使用XML概要(Schema)和XML綁定處理引擎,您可以半自動地將滿足某個XML?概要的XML數(shù)據(jù)轉(zhuǎn)變成Java數(shù)據(jù)對象。代表性的引擎是Castor,是由ExoLab小組管理的一個開放源代碼項目的產(chǎn)物。上述使用Xerces?DOM的簡單例子僅僅是演示了這一處理過程的底層模型。?
          上述示例表明,在Java環(huán)境中解析或產(chǎn)生XML是非常方便的,這與J2EE沒有必然關(guān)聯(lián)。格式化為XML的數(shù)據(jù)可以從應(yīng)用程序的任何層次流入或輸出,這使得與外部系統(tǒng)的集成性無可限量。但我們能否以一種更為直接的方式將XML數(shù)據(jù)源集成到J2EE架構(gòu)中去呢??


          駕馭消息?

          J2EE架構(gòu)包含了對JMS(Java消息服務(wù))API的訪問,以實現(xiàn)面向消息的通信(J2EE?1.2.1版只需JMS?API即可,在J2EE?1.3版中JMS基本定型,此時必須由某個兼容J2EE平臺的服務(wù)器提供一個JMS?API?Provider)。這一類的異步交互(與之相對的是:本地或遠(yuǎn)程方法調(diào)用所代表的同步交互)被證明在某些應(yīng)用環(huán)境中是非常有用的。某些時候,交互只需要通過間接的請求或回答來實現(xiàn),即:在某些情況下,發(fā)出消息后不可能立即收到答復(fù),但我們?nèi)韵M?dāng)消息發(fā)出者重新在線時,確保他能收到答復(fù)信息。?
          面向消息系統(tǒng)的實際應(yīng)用之一就是企業(yè)之間的松散集成。類似于EDI(電子文檔交換)時代的文檔交換,兩個企業(yè)由于業(yè)務(wù)的需要而交換消息,此時通常不能為了使用RPC或者RMI、CORBA、DCOM之類的遠(yuǎn)程方法交互而在兩者之間進行緊密集成。象JMS?API這樣的消息系統(tǒng)允許雙方交換基于JMS?API的消息載荷,前提是雙方在會話的時候均能提供兼容的JMS?API服務(wù)。當(dāng)前仍然存在的困難是:雙方是否能尊從相同的格式或協(xié)議。?
          這正是XML大顯身手的時候。XML明確地被設(shè)計來解決此類數(shù)據(jù)交換問題??靈丹妙藥就是“面向消息的概要表”(Message-Oriented?Communication?Scheme),實質(zhì)就是基于一個雙方認(rèn)同的DTD或schema,用XML格式來交換消息載荷。?
          JMS?API支持好幾種消息,其中的TextMessage代表文本消息載荷。一個簡單而有效的XML消息交換方案是,在一端將我們的XML文檔插入TextMessage,然后在另一端用自制的XML解析程序(如前面的MediaParser)解開數(shù)據(jù)并(可選地)將其轉(zhuǎn)換成Java對象。這使得我們既可以用JMS?API支持的公開預(yù)訂的消息模型,也可以用JMS?API支持的點對點的消息模型來發(fā)送XML消息。?
          上述方法有一些局限,因為對于JMS運行時處理而言,XML的內(nèi)容基本上是不透明的。例如,JMS?API允許使用基于特定消息頭的路由。這很容易理解,尤其當(dāng)我們希望XML消息根據(jù)其內(nèi)容采取不同走向時。例如在我們的MediaAsset例子中,我們希望公開講座內(nèi)容,但只想把特定的內(nèi)容傳送給那些預(yù)訂了課程的人,或傳送給那些表明可以接受某些媒體格式(如視頻流)的人。為了發(fā)揮JMS?API的價值,以便實現(xiàn)上述基于內(nèi)容的消息路由,我們有必要從XML數(shù)據(jù)中解析出關(guān)鍵信息,然后在構(gòu)造標(biāo)準(zhǔn)JMS?API消息頭時插入這些信息。這是可行的,但要實現(xiàn)XML信息我們就得額外地寫很多代碼(交換消息的雙方均如此)。?
          為了在XML和JMS?API之間架起橋梁,一些廠商提供了自定義的JMS擴展,以便直接支持XML消息機制。例如,BEA系統(tǒng)公司基于J2EE的WebLogic應(yīng)用服務(wù)器特別為TextMessage提供了XMLMessage子類,允許用XPath表達式來過濾XML消息。不過這是一種專有的擴展,這要求交換消息的雙方必須都能處理這類消息。?
          為此,Sun公司目前正在開發(fā)用于XML消息的Java?API(JAXM)。其目標(biāo)是提供一個高級別的標(biāo)準(zhǔn)服務(wù),以實現(xiàn)基于ebXML的消息的合成與傳送。一個JAXM服務(wù)提供程序可以將這類消息映射到適當(dāng)?shù)奈锢硐⑾到y(tǒng)(諸如JMS?API)中去。?
          讓XML看得見?
          將XML同Web系統(tǒng)的用戶界面進行集成顯然是一種有益的嘗試。絕大多數(shù)的界面程序,無論是基于還是不基于Web,都是將數(shù)據(jù)進行轉(zhuǎn)換,然后用易讀的格式展現(xiàn)給用戶。用諸如XML這種“易消化”的格式存放數(shù)據(jù)將簡化上述工作,同時它還大大提高了內(nèi)容的可管理性,接下來我們就可看到這一點。不過首先要大書一筆的是,XML在Web界面層的應(yīng)用得益于JSP技術(shù)的發(fā)展。?
          一直以來大家都希望能清晰地區(qū)分Web應(yīng)用程序的表示層與底層對象模型,JSP框架誕生于這些努力之中(包括早期JHTML嘗試)。JSP框架允許將Java代碼嵌入到HTML內(nèi)容中,這樣既可以實現(xiàn)動態(tài)內(nèi)容,又不必經(jīng)常修改Java?Servlets的代碼。在頁面中包含Java技術(shù)的途徑是通過JSP標(biāo)記(JSP?Tags),這些標(biāo)記以XML風(fēng)格出現(xiàn)。在JSP中,Java程序以代碼片段、服務(wù)器端JavaBeans組件、在服務(wù)器端觸發(fā)特定操作的不透明標(biāo)記(標(biāo)準(zhǔn)的或自定義的)等形式存在。當(dāng)某個用戶通過瀏覽器請求JSP頁面時,一個Java應(yīng)用服務(wù)器解析該JSP頁面,將其編譯成一個Java?Servlet,然后執(zhí)行該Servlet以產(chǎn)生答復(fù)頁面。?
          一種直接將XML數(shù)據(jù)源集成到JSP的界面中去的方法是,將XML加載到JavaBeans組件中(如同我們在MediaAsset例子中所做的),然后在JSP中直接引用這些JavaBeans組件。?
          下面是一個嵌入Java代碼片斷的例子:?
          <html>?
          <head>?
          <title>第14講的媒體資源</title>?
          </head>?
          <body>?
          <!--?引入我們的類?-->?
          <%@?page?import="jaf.xml.*"?%>?
          <center><H3>Media?Assets?for?Lecture?14:</H3></center>?
          <!--?定義一個資源對象,以便用于顯示?-->?
          <jsp:useBean?class="jaf.xml.MediaAsset"?id="asset"?/>?
          <!--?從一個先前定義的位置裝載資源?-->?
          <%?MediaParser?parser?=?new?MediaParser();?
          Collection?assets?=?parser.loadAssets("http://javaschool.org?
          /jaf/E162/lecture14-assets.xml");?
          Iterator?iter?=?assets.iterator();?
          %>?
          <table?border=0>?
          <tr><th>Name</th><th>Type</th><th>URN</th></tr>?
          <%?
          while?(iter.hasNext())?{?
          asset?=?(MediaAsset)iter.next();?
          %>?
          <tr><td><jsp:getProperty?name="asset"?property="name"?/></td>?
          <td><jsp:getProperty?name="asset"?property="type"?/></td>?
          <td><jsp:getProperty?name="asset"?property="URN"?/></td>?
          </tr>?
          <%?
          }?
          %>?
          </table>?
          </body>?
          </html>?
          其中粗體部分為JSP代碼片斷和標(biāo)記,其余部分是標(biāo)準(zhǔn)的HTML文本。?
          上述程序還有一種更簡潔的寫法,那就是使用自定義JSP頁面標(biāo)記。這樣我們就可以從JSP頁面中剔出代碼段,只使用JavaBeans組件和自定義的JSP標(biāo)記即可。比如說,為了去掉創(chuàng)建解析器、加載資源數(shù)據(jù)到集合中的那段代碼,我們可創(chuàng)建一個自己的標(biāo)記,由它在幕后完成這些工作。以下是例子:?
          .?
          .?
          .?
          <!--?引入我們的類?-->?
          <%@?page?import="jaf.xml.*"?%>?
          <center><H3>Media?Assets?for?Lecture?14:</H3></center>?
          <!--?加載我們自定義的標(biāo)記庫?-->?
          <%@?taglib?uri="http://javaschool.org/taglib"?prefix="media"?%>?
          <!--?從一個先前定義的位置裝載資源?-->?
          <media:load?url="http://javaschool.org/jaf/E162/lecture14-assets.xml"?
          collectionName="assets"?cursorName="asset"?/>?
          <table?border=0>?
          .?
          .?
          .?
          使用自定義標(biāo)記的最大好處是使我們的程序代碼集中在一個地方(對Java技術(shù)而言,一般是指在“類”中),易于管理。這樣可以將程序中對象層同界面層的集成關(guān)系定義得很清晰,修改代碼所造成的影響是可以預(yù)測和管理的。?
          直接將XML數(shù)據(jù)轉(zhuǎn)換成Web顯示內(nèi)容的另一種方法是使用XSL和XSLT。在這種方案中,將XML數(shù)據(jù)映射成HTML(或WML等)的邏輯由XSL樣式表(XSL?StyleSheet)來定義。樣式表描述了每個特定XML數(shù)據(jù)實體應(yīng)該怎樣轉(zhuǎn)換成界面數(shù)據(jù)實體(如HTML表格、內(nèi)聯(lián)標(biāo)記等)。在JSP架構(gòu)中,XSL轉(zhuǎn)換只能應(yīng)用于特定的XML數(shù)據(jù)源,最理想的是采用一套自定義的JSP標(biāo)記并引用某個XSLT處理程序。這方面的典型示例請參考java.sun.com中關(guān)于XML同JSP構(gòu)架集成的白皮書。?
          同前面那個JSP自定義標(biāo)記加XML解析器組件的方案相比,XSLT方案的伸縮性要好一些,而且具有更好的可管理性。在這種情形下,我們的轉(zhuǎn)換邏輯是編寫在一個XSL樣式表中,而不是在Java代碼中。這意味著當(dāng)需要修改界面時,大多數(shù)情況下只是編輯樣式表或者HTML,代碼不受影響。不過在決定選用何種方案之前,還是要根據(jù)實際狀況仔細(xì)權(quán)衡。如果選用XSLT方案,那么就得有人負(fù)責(zé)維護這些XSL樣式表(要么是負(fù)責(zé)界面的人,要么是編寫程序的人)。XSLT既像內(nèi)容,又像程序,因此雙方都不能把責(zé)任推給對方,結(jié)果大家可能都被這不倫不類的XSLT弄得矛盾百出。從這點上考慮,采用自定義標(biāo)記并由界面開發(fā)者將其嵌入表示層的方法似乎更有吸引力,因為這樣軟件工程師只考慮Java代碼,而內(nèi)容工程師也只操心內(nèi)容標(biāo)記。?
          Java?servlet過濾器是J2EE?1.3版在其Web層最新發(fā)布的一種Web組件。當(dāng)Sevelet將請求寫入某個資源或者從某個資源中讀取回答信息時,過濾器可以非常方便地轉(zhuǎn)換其中的頭信息和內(nèi)容信息。這里所說的資源可以是一個Java?servlet、一個JSP頁面,甚至一個靜態(tài)Web頁。過濾器的確很“酷”,因為它允許開發(fā)人員從轉(zhuǎn)換內(nèi)容的代碼中分離出生成內(nèi)容的那部分代碼,并加以重用。當(dāng)需要通過XSLT方式將XML數(shù)據(jù)轉(zhuǎn)換到不同的XML應(yīng)用目標(biāo)時,Java?servlet過濾器尤其有用。?
          在J2EE應(yīng)用程序中使用Java?servlet過濾器轉(zhuǎn)換其輸出,以便兼容任何類型客戶端的前景呼之欲出。servlet過濾器能夠偵測到來自使用WAP協(xié)議(無線應(yīng)用協(xié)議)的移動客戶端的呼叫,并且將答復(fù)內(nèi)容轉(zhuǎn)換成WML(無線標(biāo)記語言)格式。servlet過濾器也能檢測到來自iMode無線客戶的呼叫,并將其轉(zhuǎn)變成cHTML(緊湊HTML)格式。當(dāng)然,servlet過濾器也能夠分辨出傳統(tǒng)的HTML瀏覽器客戶的請求,并用正確的格式進行回復(fù)。?
          結(jié)束語?
          在J2EE?1.2.1規(guī)范中,XML“集成”僅指組件或應(yīng)用程序的XML格式的部署描述。在J2EE?1.3規(guī)范中,對XML的支持被擴展為要求具備SAX?2和DOM?2解析器,以及在兼容J2EE的服務(wù)器平臺上提供XSLT轉(zhuǎn)換處理程序。您可以毋庸置疑地相信,將來在J2EE架構(gòu)中還會集成進更多的XML特性,因為J2EE規(guī)范的定義者們會認(rèn)真傾聽開發(fā)者社區(qū)中對在企業(yè)級應(yīng)用中使用更多XML的渴求呼聲。例如,JSR(Java定義請求)處理小組中與JAXM規(guī)范相關(guān)的部分(JSR?000067)承諾在J2EE后續(xù)規(guī)范中集成進JAXM。可以預(yù)見,在JSP架構(gòu)、EJB和JDBC規(guī)范中均會有類似的變化。J2EE平臺中上述組件的變革,將使Java技術(shù)開發(fā)者目前用的XML更為規(guī)范化(以及標(biāo)準(zhǔn)化),發(fā)揮出更大的威力。
          posted on 2006-07-20 12:07 MEYE 閱讀(681) 評論(0)  編輯  收藏 所屬分類: JAVA
          主站蜘蛛池模板: 五峰| 大田县| 彭山县| 姜堰市| 新田县| 临江市| 西吉县| 鹤壁市| 马公市| 大悟县| 华阴市| 扎赉特旗| 永泰县| 遂宁市| 新宾| 静宁县| 涞源县| 古田县| 修武县| 商丘市| 扶沟县| 杭州市| 浠水县| 屯昌县| 丹巴县| 雷州市| 鞍山市| 平遥县| 清远市| 阿尔山市| 抚宁县| 广州市| 务川| 上虞市| 青海省| 嘉定区| 安顺市| 阜新| 铜山县| 新余市| 资兴市|