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

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

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

    隨筆-0  評(píng)論-3  文章-28  trackbacks-0

    1.     10.   JDBC類庫(kù)

    11.   常用設(shè)計(jì)模式

     

     

     

     

    --- 本文檔旨在對(duì)我們常用的一些Java API做一些總結(jié), 目的是讓我們能夠正確有效的使用Java的類庫(kù)。 技巧也就是前人經(jīng)驗(yàn)的一種總結(jié)。

     

     

     

     

     

    1.   Java面向?qū)ο蠡靖拍?/span>

     

     

    Java基本上是面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言, 除了一些簡(jiǎn)單類型(primitive)的變量以外,一切都是對(duì)象, 程序是對(duì)象的組合, 每個(gè)對(duì)象都有自己的空間, 并且每個(gè)對(duì)象都有一種類型, 同一類所有對(duì)象都能接受相同的消息。 下面只對(duì)Java中對(duì)象的結(jié)構(gòu)作簡(jiǎn)單的說(shuō)明:

     

     

    Ø         類(class:  class是定義類的關(guān)鍵字, 類中包含類變量, 方法, 內(nèi)部類, 內(nèi)部接口等。由class可以生成類的實(shí)例, 即一個(gè)個(gè)對(duì)象。 如果一個(gè)類的成員被定義成static的,則這個(gè)成員不專屬于任何對(duì)象, 而是屬于這個(gè)類, 所有的對(duì)象共享這個(gè)成員。

     

     

    Ø         抽象類(abstract class): 抽象類不能直接生成一個(gè)實(shí)例, 抽象類中必需有方法是abstract的,抽象類的意思就是它實(shí)現(xiàn)了一部分的方法, 而定義為abstract的方法則需要在它的字類中去實(shí)現(xiàn)。

     

     

    Ø         接口(interface): 接口可以理解為純抽象的類, 它的每個(gè)方法都是未實(shí)現(xiàn)的, 它可以有成員變量, 但必須是static的。 一個(gè)類如果從這個(gè)接口繼承(implements)則它必須實(shí)現(xiàn)這個(gè)接口的所有方法。

     

     

    繼承類用關(guān)鍵字:extends,繼承接口用關(guān)鍵字:implements。 一個(gè)類只能從一個(gè)類繼承下來(lái), 但可以從多個(gè)接口繼承(類似于C++的多重繼承)。 字類可以覆蓋父類的方法(method), 但不能覆蓋父類的成員變量(field)。 如果父類的方法為finalstatic的則不能被覆蓋。類的初始化順序是, 如果有父類, 則先初始化父類的field,然后執(zhí)行父類的構(gòu)造函數(shù), 如果子類沒有顯式的去調(diào)父類的構(gòu)造函數(shù)則缺省的會(huì)去調(diào)父類的無(wú)參數(shù)構(gòu)造函數(shù)。 然后是子類的field與構(gòu)造函數(shù)的初始化。

     

     

     

     

    public interface SuperInterface {

     

     

                 public staitc String SOME_FLAG = “1”;

     

     

                 public void someMethod();

     

     

    }

     

     

     

     

    public Class SuperClass {

     

     

                 {

     

     

                        System.out.println(“init SuperClass field”);

     

     

                 }

     

     

     

     

                 public SuperClass() {

     

     

                        System.out.println(“init SuperClass Constructor”);

     

     

                 }

     

     

     

     

                 public void runMethod() {

     

     

                        System.out.println(“run SuperClass runMethod()”);

     

     

                 }

     

     

    }

     

     

     

     

    public Class SubClass extends SuperClass implements SuperInterface {

     

     

                 {

     

     

                        System.out.println(“init SubClass field”);

     

     

                 }

     

     

     

     

          public SubClass() {

     

     

                        System.out.println(“init SubClass Constructor”);

     

     

                 }

     

     

     

     

                 public void someMethod() {

     

     

                        System.out.println(“run SubClass someMethod()”);

     

     

                 }

     

     

     

     

                 public void runMethod() {

     

     

                        System.out.println(“run SubClass runMethod()”);

     

     

                 }

     

     

    }

     

     

    有以下test代碼:

     

     

    public class Test {

     

     

    public void main(String[] args) {

     

     

           SubClass sub = new SubClass();

     

     

           sub. runMethod();

     

     

    }

     

     

    }

     

     

    則會(huì)輸出:

    init SuperClass field

     

     

    init SuperClass Constructor

     

     

    init SubClass field

     

     

    init SubClass Constructor

     

     

    run SubClass runMethod()

     

     

    以下章節(jié)所講述到的常用的Java API就是一些Java自帶的一些ClassInterface的用法。

    2System

     

    System類位于package java.lang下面, 凡是此package下面的類我們可以直接引用無(wú)需先import進(jìn)來(lái), 因?yàn)?/span>JVM缺省就load了這下面的所有class。

    System包含了一些我們常用的方法與成員變量。 System不能被實(shí)例化, 所有的方法都可以直接引用。 主要作用大致有:

    Ø         輸入輸出流:
    (PrintStream) System.out
    (標(biāo)準(zhǔn)終端輸出流),
    (PrintStream) System.err
    (標(biāo)準(zhǔn)錯(cuò)誤輸出流),
    (InputStream) System.in
    (標(biāo)準(zhǔn)輸入流)。
    我們還可以重定向這些流, 比如將所有的System.out的輸出全部重定向至一文件中去。
    SystemsetOut(PrintStream)
    標(biāo)準(zhǔn)輸出重定向
    System.setErr(PrintStream)
    標(biāo)準(zhǔn)錯(cuò)誤輸出重定向
    System.setIn(InputStream)
    標(biāo)準(zhǔn)輸入重定向

    Ø         取當(dāng)前時(shí)間:
    System.currentTimeMillis()
    所取到的時(shí)間是從1970/01/01以來(lái)1/1000秒計(jì)算的long型值。這個(gè)值可以轉(zhuǎn)換至DateTimestamp值。 它一般還可以用來(lái)計(jì)算程序執(zhí)行的時(shí)間。例:
    long beginTime = System. currentTimeMillis();


    System.out.println(“run time = ” + (System. currentTimeMillis() – beginTime));

    Ø         數(shù)組拷貝:
    System.arraycopy(Object src, int src_position, Object dst, int dst_position, int length)
    src
    : 源數(shù)組。
    src_position
    : 源數(shù)組拷貝的起始位置。
    dst
    : 目標(biāo)數(shù)組
    dst_position
    : 拷貝至目標(biāo)數(shù)組的起始位置
    length
    : 拷貝元素的長(zhǎng)度
    利用System.arraycopy進(jìn)行數(shù)組的拷貝效率是最高的, 一般情況下我們自己很少直接用到這個(gè)方法,但在集合類的內(nèi)部中都大量使用了這個(gè)方法。
    例:
    int[] array1 = {1, 2, 3, 4, 5};

    int[] array2 = {4, 5, 6, 7, 8};
    int array3 = new int[8];
    System.arraycopy(
    array1, 0, array3, 0, 5);
    System.arraycopy(
    array2, 2, array3, 5, 3);
    此時(shí)array3 = {1, 2, 3, 4, 5, 6, 7, 8}

    這比用for循環(huán)來(lái)進(jìn)行賦值效率要高。

     

     

    Ø         存取系統(tǒng)的Properties
    System.getProperties()
    :取得當(dāng)前所有的Properties, Properties將在后面的集合一節(jié)進(jìn)行詳細(xì)的論述。
    System.setProperties(Properties props)
    :設(shè)置系統(tǒng)的Properties
    System.getProperty(String key)
    : 根據(jù)一個(gè)鍵值來(lái)取得一個(gè)Property。
    System.setProperty(String key, String value)
    : 設(shè)置系統(tǒng)的一個(gè)Property。
    JVM
    起動(dòng)的時(shí)候?qū)?huì)有一些缺省的Properties值, 例如:
    java.version Java
    運(yùn)行環(huán)境版本
    java.home Java
    主目錄 installation directory
    java.class.path Java
    class path
    java.ext.dirs Java
    的擴(kuò)展目錄路徑

    file.separator
    文件分隔符("/" on UNIX)
    path.separator
    路徑分隔符
    (":" on UNIX)
    line.separator
    行分隔符
    ("\n" on UNIX)
    user.name
    用戶名

    user.home
    用戶主目錄

    user.dir 用戶當(dāng)前工作目錄
    更詳細(xì)的信息請(qǐng)參照Java API。 另外在起動(dòng)一個(gè)java程序的時(shí)候可以通過(guò)-D來(lái)設(shè)置系統(tǒng)的Property, 比如 java –Dejb.file=ejb_Test PrintTest PrintTest里面就可以通過(guò)System.getProperty(ejb.file)來(lái)取得值ejb_Test。

     

     

    Ø         其它
    System.
    loadLibrary(String libname) 加載native的動(dòng)態(tài)庫(kù)。 可以用CJNI的庫(kù), 然后在java中通過(guò)native方法來(lái)調(diào)用。
    System.setSecurityManager(SecurityManager s)
    System.getSecurityManager()
    設(shè)置與取得系統(tǒng)的security class。

     

     

     

     

    3String, StringBuffer

     

    3.1 基本用法

     

    String可以說(shuō)是我們最常用的一個(gè)類, 熟練掌握它的一些基本用法是很有用的。

    String是由一組字符組成的字符串, 下標(biāo)由0開始。 一旦有必要改變?cè)瓉?lái)的內(nèi)容, 每個(gè)String方法都有返回了一個(gè)新的String對(duì)象。

    Ø         char charAt(int index) 返回指定位置的字符。

    Ø         int compareTo(Object o)
    int compareTo(String anotherString)
    與另外一個(gè)對(duì)象進(jìn)行比較。

    Ø         int compareToIgnoreCase(String str) 與另一個(gè)String進(jìn)行比較, 不區(qū)分大小寫

    Ø         String concat(String str) 連接兩字符串, 可以直接用+, 因?yàn)?/span>JavaString覆蓋了+

    Ø         static String copyValueOf(char[] data)
    static String copyValueOf(char[] data, int offset, int count)
    data數(shù)組轉(zhuǎn)換至String

    Ø         boolean endsWith(String suffix) 測(cè)試此String是否以suffix結(jié)尾。
    boolean startsWith(String prefix)
    測(cè)試此String是否以prefix開頭。

    Ø         boolean equals(Object anObject)
    boolean equalsIgnoreCase(String anotherString)
    比較兩字符串的值。 不相等則返回false

    Ø         byte[] getBytes() 根據(jù)缺省的字符編碼將String轉(zhuǎn)換成字節(jié)數(shù)組。
    byte[] getBytes(String enc)
    根據(jù)指定的編碼將String轉(zhuǎn)換萬(wàn)字節(jié)數(shù)組。

    Ø         void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 拷貝字符至一數(shù)組中

    Ø         int indexOf(int ch) 從字串的起始位置查找字符ch第一次出現(xiàn)的位置
    int indexOf(int ch, int fromIndex)
    從指定的fromIndex位置向后查找第一次出現(xiàn)ch的位置,
    int indexOf(String str)
    int indexOf(String str, int fromIndex)
    如果不存在chstr都返回-1

    Ø         int lastIndexOf(int ch) 從字串的最終位置往前查找第一次出現(xiàn)ch的位置
    int lastIndexOf(int ch, int fromIndex) 
    從指定的位置往前查找第一次出現(xiàn)ch的位置,
    int lastIndexOf(String str)
    int lastIndexOf(String str, int fromIndex)
    如果不存在則返回-1

    Ø         int length() 該字符串的字符長(zhǎng)度(一個(gè)全角的漢字長(zhǎng)度為1

    Ø         String replace(char oldChar, char newChar) 將字符oldChar全部替換為newChar 返回一個(gè)新的字符串。

    Ø         String substring(int beginIndex) 返回從beginIndex開始的字符串子集
    String substring(int beginIndex, int endIndex)
    返回從beginIndexendIndex結(jié)束的字符串的子集。 其中endIndex – beginIndex等于子集的字符串長(zhǎng)度

    Ø         char[] toCharArray() 返回該字符串的內(nèi)部字符數(shù)組

    Ø         String toLowerCase() 轉(zhuǎn)換至小寫字母的字符串
    String toLowerCase(Locale locale)
    String toUpperCase()
    轉(zhuǎn)換至大寫字母的字符串
    String toUpperCase(Locale locale)

    Ø         String toString() 覆蓋了ObjecttoString方法, 返回本身。

    Ø         String trim() 將字符串兩邊的半角空白字符去掉, 如果需要去掉全角的空白字符得要自己寫。

    Ø         static String valueOf(primitive p) 將其它的簡(jiǎn)單類型的值轉(zhuǎn)換為一個(gè)String

     

     

    StingBuffer是一個(gè)可變的字符串,它可以被更改。同時(shí)StringBufferThread safe的, 你可以放心的使用, 常用的方法如下:

    Ø         StringBuffer append(param)  StringBuffer對(duì)象之后追加param(可以為所有的簡(jiǎn)單類型和Object) 返回追加后的StringBuffer 與原來(lái)的對(duì)象是同一份。

    Ø         char charAt(int index) 返回指定位置index的字符。

    Ø         StringBuffer delete(int start, int end) 刪除指定區(qū)域start~end的字符。

    Ø         StringBuffer deleteCharAt(int index) 刪除指定位置index的字符。

    Ø         void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) StringgetChars方法

    Ø         StringBuffer insert(int offset, boolean b) 在指定位置offset插入param(為所有的簡(jiǎn)單類型與Object)

    Ø         int length() Stringlength()

    Ø         StringBuffer replace(int start, int end, String str) 將指定區(qū)域start~end的字符串替換為str

    Ø         StringBuffer reverse() 反轉(zhuǎn)字符的順序

    Ø         void setCharAt(int index, char ch) 設(shè)置字符chindex位置。

    Ø         String substring(int start)

    Ø         String substring(int start, int end) StringsubString

    Ø         String toString() 返回一個(gè)String

     

     

    大家可能已經(jīng)注意到很多方法都返回了一個(gè)StringBuffer對(duì)象, 但返回的這個(gè)對(duì)象與String的方法返回的String不一樣, 返回的StringBuffer對(duì)象與被操作的StringBuffer對(duì)象是同一份, String的方法返回的String則肯定是重新生成的一個(gè)String

    3.2性能對(duì)比

     

    因?yàn)?/span>String被設(shè)計(jì)成一種安全的字符串, 避免了C/C++中的尷尬。因此在內(nèi)部操作的時(shí)候會(huì)頻繁的進(jìn)行對(duì)象的交換, 因此它的效率不如StringBuffer。 如果需要頻繁的進(jìn)行字符串的增刪操作的話最好用StringBuffer 比如拼SQL文, 寫共函。 另: 編繹器對(duì)String+操作進(jìn)行了一定的優(yōu)化。

    x = "a" + 4 + "c"

    會(huì)被編繹成

    x = new StringBuffer().append("a").append(4).append("c").toString()

    但:

    x = “a”;

    x = x + 4;

    x = x + “c”;

    則不會(huì)被優(yōu)化。 可以看出如果在一個(gè)表達(dá)式里面進(jìn)行String的多次+操作會(huì)被優(yōu)化, 而多個(gè)表達(dá)式的+操作不會(huì)被優(yōu)化。

     

     

    3.3技巧

     

    1.       Servlet2.3JSP1.1以前畫面post到后臺(tái)的數(shù)據(jù)是通過(guò)ISO88591格式進(jìn)行編碼的, 則當(dāng)遇到全角日文字的時(shí)候, 在后臺(tái)request得到的數(shù)據(jù)可能就是亂碼, 這個(gè)時(shí)候就得自己進(jìn)行編碼轉(zhuǎn)換, 通過(guò)String.getBytes(String enc)方法得到一個(gè)字節(jié)流, 然后通過(guò)String(byte[] bytes, String enc)這個(gè)構(gòu)造函數(shù)得到一個(gè)用新的編碼生成的字符串. 例如將ISO88591的字符串轉(zhuǎn)換成Shift_JIS的字符串, 方法如下:

    public static String convertString(String str) {

     

     

           if (str == null) {

     

     

                  return null;

     

     

           }

     

     

          

     

     

           try {

     

     

                  byte[] buf = str.getBytes("ISO8859_1");

     

     

                  return new String(buf, "Shift_JIS");

     

     

           } catch (Exception ex) {

     

     

                  ex.printStackTrace();

     

     

                  return null;

     

     

           }

     

     

    }

     

     

    不過(guò)在最新的Servlet2.3Jsp1.2中可以通過(guò)request.setCharacterEncoding來(lái)進(jìn)行設(shè)置取值的碼制, 不需要自己再做轉(zhuǎn)換。

     

     

    2.因?yàn)?/span>Java在計(jì)算String的長(zhǎng)度是以字符為單位的, 因此一個(gè)全角與半角的字符長(zhǎng)度是一樣的, 但是DB中往往是根據(jù)字節(jié)來(lái)計(jì)算長(zhǎng)度的, 因此我們?cè)谧?/span>Check的時(shí)候得要判斷String的字節(jié)長(zhǎng), 可以用以下的方法:

    public static String length(String str) {

     

     

          

     

     

           if (str == null) {

     

     

                  return 0;

     

     

           }

     

     

          

     

     

           return str.getBytes().length;

     

     

    }

     

     

     

     

    4.?dāng)?shù)值,字符,布爾對(duì)象與簡(jiǎn)單類型的操作

     

    簡(jiǎn)單的對(duì)照表如下:

     

     

    Object

    Primitive

    范圍

    Number

    Long

    long

    -9223372036854775808 to 9223372036854775807

    Integer

    int

    -2147483648 to 2147483647

    Short

    short

    -32768 to 32767

    Byte

    byte

    -128 to 127

    Double

    double

     

     

    Float

    float

     

     

    Character

    char

    '\u0000' to '\uffff'

    Boolean

    boolean

    false and true

     

     

    C等其它語(yǔ)言不同的是數(shù)值的范圍不隨平臺(tái)的改變而改變, 這就保證了平臺(tái)之間的統(tǒng)一性,提高了可移植性。

     

     

    Number: Number本身是個(gè)抽象類, 不能直接使用, 所有直接從Number繼承下來(lái)的子類都有以下幾種方法:

    Ø         byte byteValue() 返回字節(jié)值

    Ø         double doubleValue() 返回double

    Ø         float floatValue() 返回float

    Ø         int intValue() 返回float

    Ø         long longValue() 返回long

    Ø         short shortValue() 返回short

    在需要通過(guò)Object來(lái)取得簡(jiǎn)單數(shù)據(jù)類型的值的時(shí)候就得用到以上的方法, 不過(guò)我不推薦不同類型之間的取值, 比如Long型的Object不要直接去調(diào)用intValue(),精度可能會(huì)丟失。

     

     

    如果想通過(guò)String來(lái)得到一個(gè)數(shù)值類型的簡(jiǎn)單類型值, 一般在每個(gè)Number的類里面都有一個(gè)parseXXX(String)的靜態(tài)方法, 如下:

    Ø         byte Byte.parseByte(String s)

    Ø         double Double.parseDouble(String s)

    Ø         float Float.parseFloat(String s)

    Ø         int Integer.parseInt(String s)

    Ø         long Long.parseLong(String s)

    Ø         short Short.parseShort(String s)

     

     

    如果想直接從String得到一個(gè)Number型的Object,則每個(gè)Number類里面都有valueOf(String s) 這個(gè)靜態(tài)方法。如:

    Ø         Byte Byte.valueOf(String s)

    Ø         Double Double.valueOf(String s)

    Ø         Float Float.valueOf(String s)

    Ø         Integer Integer.valueOf(String s)

    Ø         Long Long.valueOf(String s)

    Ø         Short Short.valueOf(String s)

    一般的在構(gòu)造一個(gè)Number的時(shí)候都可以通過(guò)一個(gè)String來(lái)完成, 比如:

    Long longObject = new Long(“1234567890”);

     

     

    等價(jià)于

    Long longObject = Long.valueOf(“1234567890”);

     

     

     

     

    因?yàn)槊總€(gè)Number的子類都實(shí)現(xiàn)了ObjecttoString()方法, 所以, 如果想得到一個(gè)String型的數(shù)值, 直接調(diào)用XXX.toString()就可以了。 如果想得到一個(gè)簡(jiǎn)單類型的String, 方法很多總結(jié)如下:

    Ø         首先生成對(duì)應(yīng)的Number Object類型, 然后調(diào)用toString()

    Ø         調(diào)用Number子類 .toString(type t) 其中t就是簡(jiǎn)單類型的數(shù)據(jù)。

    Ø         調(diào)用String.valueOf(type t) (推薦使用這種方法)

     

     

    大家可以看出, 往往一種結(jié)果可以用多種方法實(shí)現(xiàn), 總的原則就是深度最少優(yōu)先。比如由一個(gè)String得到一個(gè)簡(jiǎn)單類型的值可以有以下兩種方法:

    Integer.parseInt(“12345”);

     

     

    (new Integer(s)).intValue(“12345”);

     

     

    我們當(dāng)然應(yīng)該使用第一種方法。

     

     

    Character: Character對(duì)應(yīng)著char類型, Character類里面有很多靜態(tài)的方法來(lái)對(duì)char進(jìn)行判斷操作, 在此不一一講述, 詳細(xì)的操作請(qǐng)參照JDK API。 需要提醒的是, Java對(duì)字符的判斷操作基本都是以Unicode進(jìn)行的, 比如Character.isDigit(char ch)這個(gè)方法, 不光半角的0-9符合要求, 全角的日文0-9也是符合要求的。

     

     

    Boolean: Boolean對(duì)應(yīng)著boolean類型, boolean只有truefalse兩個(gè)值, 不能與其它數(shù)值類型互換, 可以通過(guò)字符串”true”以及”false”來(lái)得到ObjectBoolean, 也可以通過(guò)簡(jiǎn)單類型的boolean得到Boolean 常用方法如下:

    Ø         Boolean(boolean value) 通過(guò)簡(jiǎn)單類型的boolean構(gòu)造Boolean

    Ø         Boolean(String s) 通過(guò)String(“true”, “false”)構(gòu)造Boolean

    Ø         boolean booleanValue() ObjectBoolean得到簡(jiǎn)單類型的boolean

    Ø         boolean equals(Object obj) 覆蓋了Object.equals方法, Object值比較

    Ø         static Boolean valueOf(String s) 功能與構(gòu)造函數(shù)Boolean(String s)一樣

     

     

     

     

    5Class, ClassLoader

     

    Java是一種介于解釋與編繹之間的語(yǔ)言, Java代碼首先編繹成字節(jié)碼, 在運(yùn)行的時(shí)候再翻譯成機(jī)器碼。 這樣在運(yùn)行的時(shí)候我們就可以通過(guò)Java提供的反射方法(reflect)來(lái)得到一個(gè)ObjectClass的額外信息, 靈活性很大,可以簡(jiǎn)化很多操作。

     

     

    Class: 任何一個(gè)Object都能通過(guò)getClass()這個(gè)方法得到它在運(yùn)行期間的Class。 得到這個(gè)Class之后可做的事情就多了, 比如動(dòng)態(tài)得到它的構(gòu)造函數(shù), 成員變量, 方法等等。 還可以再生成一份新的實(shí)例, 下面只給出幾個(gè)我們常用的方法, 更詳細(xì)的用法參照Java API

    Ø         Class Class.forName(String className) throws ClassNotFoundException 這是個(gè)靜態(tài)方法, 通過(guò)一個(gè)Class的全稱來(lái)得到這個(gè)Class。

    Ø         String getName() 取得這個(gè)Class的全稱, 包括package名。

    Ø         Object newInstance() 得到一個(gè)實(shí)例, 調(diào)用缺省的構(gòu)造函數(shù)。

    例如我們有一個(gè)類: com.some.util.MyClass 如果得到它的一個(gè)實(shí)例呢? 可能有以下兩種方法:

    MyClass myClass = new MyClass() 直接通過(guò)操作符new生成;

    或者:

    MyClass myClass = (MyClass) Class.forName(“com.some.util.MyClass”).newInstance();

    也許有人就會(huì)懷疑第二種方法實(shí)際意義, 能夠直接new出來(lái)干嘛繞彎。 但實(shí)際上它的用處卻很大, 舉個(gè)例子: 用過(guò)struts的人都知道, action-config.xml當(dāng)中定義了一系列的formBeanactionBean, 當(dāng)然每個(gè)formaction都具有同類型, 這樣在一個(gè)request過(guò)來(lái)的時(shí)候我可以動(dòng)態(tài)的生成一個(gè)formaction的實(shí)例進(jìn)行具體的操作, 但在編碼的時(shí)候我并不知道具體是何種的formaction, 我只調(diào)用它們父類的方法。 你如果要用第一種方法的話就很麻煩, 你得在編碼的時(shí)候通過(guò)一個(gè)標(biāo)志來(lái)判斷每一次request需要具體生成的formaction, 代碼的靈活性大大降低。 總的來(lái)說(shuō)在面向接口的編程當(dāng)中經(jīng)常使用這種方法, 比如不同數(shù)據(jù)庫(kù)廠家的JDBC Driver都是從標(biāo)準(zhǔn)的JDBC接口繼承下去的, 我們?cè)趯懗绦虻臅r(shí)候用不著管最終是何種的Driver, 只有在運(yùn)行的時(shí)候確定。 還有XMLParser也是, 我們使用的只是標(biāo)準(zhǔn)的接口, 最后到底是誰(shuí)來(lái)實(shí)現(xiàn)它的, 我們用不著去管。

     

     

    ClassLoader: ClassLoader是一個(gè)抽象類,一般的系統(tǒng)有一個(gè)缺省的ClassLoader用來(lái)裝載Class, ClassLoader.getSystemClassLoader()可以得到。不過(guò)有時(shí)候?yàn)榱税踩蛴衅渌奶厥庑枰覀兛梢宰远x自己的ClassLoader來(lái)進(jìn)行loader一些我們需要的Class 比如有的產(chǎn)品它用了自己的ClassLoader可以指定Class只從它指定的特定的JAR文件里面來(lái)loader,如果你想通過(guò)覆蓋ClassPath方法來(lái)想讓它用你的Class是行不通的。 有興趣的可以參照Java API 的更詳細(xì)的用法說(shuō)


    6. Java IO系統(tǒng)

     

     

     

    JDK1.0輸入流

     

     

    InputStream

    ByteArrayInputStream

    FileInputStream

    FilterInputStream

    ObjectInputStream

    PipedInputStream

    SequenceInputStream

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    BufferedInputStream

    DataInputStream

    PushbackInputStream

    LineNumberInputStream

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     


    JDK1.1輸入流

     

     

     

     

     

     

    Reader

     

     

     

     

     

     

     

     

     

     

     

     

    BufferedReader

    FilterReader

    PipedReader

    StringReader

    InputStreamReader

    CharArrayReader

     

     

     

     

     

     

     

     

     

     

    FileReader

    PushbackReader

    LineNumberReader

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     


    JDK1.0輸出流

     

     

     

     

     

     

    OutputStream

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    BufferedOutputStream

    DataOutputStream

    PrintStream

    ByteArrayOutputStream

    FileOutputStream

    FilterOutputStream

    ObjectOutputStream

    PipedOutputStream

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     


    JDK1.1輸出流

     

     

     

     

    Writer

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    BufferedWriter

    FilterWriter

    PipedWriter

    StringWriter

    FileWriter

    PrintWriter

    OutputStreamWriter

    CharArrayWriter

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     



    如果你剛剛接觸JavaIO部分, 你可能會(huì)感覺無(wú)從入手, 確實(shí)Java提供了過(guò)多的類,反而讓人感到很亂。

    可將Java庫(kù)的IO類分為輸入與輸出兩個(gè)部分, 1.0版本中提供了兩個(gè)抽象基類, 所有輸入的類都從InputStream繼承, 所有輸出的類都從OutputStream繼承, 1.1提供了兩個(gè)新的基類, 負(fù)責(zé)輸入的Reader與輸出的Writer, 但它們并不是用來(lái)替換原來(lái)老的InputStreamOutputStream 它們主要是讓Java能更好的支持國(guó)際化的需求。 原來(lái)老的IO流層只支持8位字節(jié)流, 不能很好地控制16Unicode字符。 Java內(nèi)含的char16位的Unicode, 所以添加了ReaderWriter層次以提供對(duì)所有IO操作中的Unicode的支持。 除此之外新庫(kù)也對(duì)速度進(jìn)行了優(yōu)化, 可比舊庫(kù)更快地運(yùn)行。

     

     

    InputStream的類型:

    1. 字節(jié)數(shù)組

    2. String對(duì)象

    3. 文件

    4. 管道, 可以從另外一個(gè)輸出流得到一個(gè)輸入流

    5. 一系列的其他流, 可以將這些流統(tǒng)一收集到單獨(dú)的一個(gè)流內(nèi)。

    6. 其他起源(如socket流等)

     

     

    還有一個(gè)是File類, Java中一個(gè)目錄也是一個(gè)文件,可以用file.isFile()file.isDirectory()來(lái)進(jìn)行判斷是文件還是目錄。 File 對(duì)象可能作為參數(shù)轉(zhuǎn)換為文件流進(jìn)行操作。 具體操作參照Java IO API

     

     

    常用方法:

     

     

    /**

     

     

     * 拼文件名, windows(\)unix(/)上的文件分割符是不一樣的

     

     

     * 可以通過(guò)File類的靜態(tài)成員變量separator取得

     

     

     */

     

     

    public static String concatFileName(String dir, String fileName) {

     

     

    String fullFileName = "";

     

     

     

     

    if (dir.endsWith(File.separator)) {

     

     

            fullFileName = dir + fileName;

     

     

    } else {

     

     

            fullFileName = dir + File.separator + fileName;

     

     

    }

     

     

     

     

    return fullFileName;

     

     

    }

     

     

     

     

    /**

     

     

     * 從控制臺(tái)讀取輸入的數(shù)據(jù), System.in (InputStream) 先轉(zhuǎn)換至InputStreamReader再用

     

     

     * BufferedReader進(jìn)行讀取.

     

     

     *

     

     

     */

     

     

    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

     

     

    String str = "";

     

     

    while (str != null) {

     

     

    str = in.readLine();

     

     

    // process(str);

     

     

    }

     

     

     

     

    /**

     

     

     * 從文件中按行進(jìn)行讀取數(shù)據(jù)處理

     

     

     */

     

     

    BufferedReader in = new BufferedReader(new FileReader("infilename"));

     

     

    String str;

     

     

    while ((str = in.readLine()) != null) {

     

     

    // process(str);

     

     

    }

     

     

    in.close();

     

     

     

     

    /**

     

     

     * 寫數(shù)據(jù)至一個(gè)新的文件中去.

     

     

     */

     

     

    BufferedWriter out = new BufferedWriter(new FileWriter("outfilename"));

     

     

    out.write("a String");

     

     

    out.close();

     

     

     

     

    /**

     

     

     * 追加新的數(shù)據(jù)到一個(gè)文件中去, 如果原文件不存在

     

     

     * 則新建這個(gè)文件.

     

     

     */

     

     

    BufferedWriter out = new BufferedWriter(new FileWriter("filename", true));

     

     

    out.write("aString");

     

     

    out.close();

     

     

     

     

    /**

     

     

     * 將一個(gè)可序列化的Javaobject以流方式寫到一個(gè)文件中去中.

     

     

     */

    ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));

     

     

    out.writeObject(object);

     

     

    out.close();

     

     

     

     

    /**

     

     

     * 從文件中恢復(fù)序列化過(guò)的Java Object

     

     

     */

     

     

    ObjectInputStream in = new ObjectInputStream(new FileInputStream("filename.ser"));

     

     

    Object object = (Object) in.readObject();

     

     

    in.close();

     

     

     

     

    /**

     

     

     * 以指定的編碼方式從文件中讀取數(shù)據(jù)

     

     

     */

     

     

    BufferedReader in = new BufferedReader(new InputStreamReader(                                                     new FileInputStream("infilename"), "UTF8"));

     

     

    String str = in.readLine();

     

     

     

     

    /**

     

     

     * 以指定的編碼方式寫數(shù)據(jù)到文件中

     

     

     */

    Writer out = new BufferedWriter(new OutputStreamWriter(

     

     

    new FileOutputStream("outfilename"), "UTF8"));

     

     

    out.write("a String");

     

     

    out.close();

     

     

     

     

     

     

    由上面的例子可以看出, 流之間可以互相轉(zhuǎn)換, 如果想對(duì)流進(jìn)行字符操作最好將之轉(zhuǎn)換成BufferedReaderBufferedWriter這樣可以提高讀寫的效率。

     

     

    需要注意的是一般來(lái)說(shuō)流的大小是得不到的, 雖然一般的InputStream都有一個(gè)available()的方法可以返回這個(gè)流可以讀到的字節(jié)數(shù), 不過(guò)這個(gè)方法有時(shí)候不會(huì)很準(zhǔn)確, 比如在讀取網(wǎng)絡(luò)傳輸?shù)牧鞯臅r(shí)候, 取到的長(zhǎng)度并不一定是真實(shí)有效的長(zhǎng)度。

     

     

    大家在寫程序的時(shí)候可能已經(jīng)注意到一些類都繼承了java.io.Serializable這個(gè)接口, 其實(shí)繼承了這個(gè)接口之后這個(gè)類的本身并不做任何事情, 只是這個(gè)類可以被序列化并通過(guò)流來(lái)進(jìn)行傳輸, 并可被還原成原Object。 這個(gè)流可以通過(guò)網(wǎng)絡(luò)傳輸(EJB 中進(jìn)行傳遞參數(shù)和返回值的Data Class), 也可以保存到文件中去(ObjectOutputStream)。

     

     

     

     

    7. Java集合類

     

    我們?cè)趯懗绦虻臅r(shí)候并不是每次只使用一個(gè)對(duì)象, 更多的是對(duì)一組對(duì)象進(jìn)行操作, 這就需要知道如何組合這些對(duì)象, 還有在編碼的時(shí)候我們有時(shí)并不知道到底有多少對(duì)象,它們需要進(jìn)行動(dòng)態(tài)的分配存放。

     

     

    Java的集合類只能容納對(duì)象句柄, 對(duì)于簡(jiǎn)單類型的數(shù)據(jù)存放, 只能通過(guò)數(shù)據(jù)來(lái)存放, 數(shù)組可以存放簡(jiǎn)單類型的數(shù)據(jù)也能存放對(duì)象。

     

     

    Java提供了四種類型的集合類: Vector(矢量) BitSet(位集) Stack(堆棧), Hashtable(散列表)。

     

     

    1.         矢量: 一組有序的元素, 可以通過(guò)index進(jìn)行訪問。

    2.         位集: 其實(shí)就是由二進(jìn)制位構(gòu)成的Vector, 用來(lái)保存大量-關(guān)信息, 它所占的空間比較小, 但是效率不是很高, 如果想高效率訪問, 還不如用固定長(zhǎng)度的數(shù)組。

    3.         堆棧: 先入后出(LIFO)集合, java.util.Stack類其實(shí)就是從Vector繼承下來(lái)的, 實(shí)現(xiàn)了pop, push方法。

    4.         散列表: 由一組組“鍵--值”組成, 這里的鍵必須是Object類型。 通過(guò)ObjecthashCode進(jìn)行高效率的訪問。

     

     

    對(duì)于這些集合之間的關(guān)聯(lián)關(guān)系見下圖, 其中標(biāo)色的部分為我們常用的類。

     

     

     

     

     

     

     

     

     

     

     

     

    由上圖可以看出, 基本接口有兩個(gè):

    Collection 所有的矢量集合類都從它繼承下去的, 但并不直接從它繼承下去的。 ListSet這兩個(gè)接口直接繼承了Collection 他們的區(qū)別是List里面可以保存相同的對(duì)象句柄, Set里面的值是不重復(fù)的。 我們經(jīng)常用的VectorArrayList就是從List繼承下去的, HashSet是從Set繼承的。

    Map散列表的接口, HashtableHashMap繼承了這個(gè)接口。

     

     

    下面給出常用集合類的常用方法。

     

     

    /**

     

     

     * Vector ArrayList的操作幾乎是一樣的

     

     

     * 常用的追加元素用add(), 刪除元素用remove()

     

     

     * 取元素用get(), 遍歷它可以循環(huán)用get(). 或者

     

     

     * 先得到一個(gè)Iterator, 然后通過(guò)遍歷Iterator的方法

     

     

     * 遍歷VectorArrayList

     

     

     */

     

     

    // 生成一個(gè)空的Vector

     

     

    Vector vector = new Vector();

     

     

    // 在最后追加一個(gè)元素。

     

     

    vector.add("one");

     

     

    vector.add("two");

     

     

    // 在指定的地方設(shè)置一個(gè)值

     

     

    vector.set(0, "new one");

     

     

    // 移走一個(gè)元素或移走指定位置的元素

     

     

    vector.remove(0);

     

     

    // for循環(huán)遍歷這個(gè)Vector

     

     

    for (int i = 0; i < vector.size(); i++) {

     

     

    String element = (String) vector.get(i);

     

     

    }

    // 用枚舉器(Enumeration)遍歷它(只有Vector有,ArrayList沒有)

     

     

    Enumeration enu = vector.elements();

     

     

    while (enu.hasMoreElements()) {

     

     

    enu.nextElement();

     

     

    }

     

     

    // 用反復(fù)器(Iterator)遍歷它

     

     

    Iterator it = vector.iterator();

     

     

    while (it.hasNext()) {

     

     

    it.next();

     

     

    }

     

     

    /**

     

     

     * HashtableHashMap的操作, 追加元素用put(不是add)

     

     

     * 刪除元素用remove, 遍歷可以用Iterator 既可以遍歷

     

     

     * 它的key, 也可以是value

     

     

     */

     

     

    // 生成一個(gè)空的HashtableHashMap

     

     

    Hashtable hashtable = new Hashtable();

     

     

    // 追加一個(gè)元素

     

     

    hashtable.put("one", "one object value");

     

     

    // 刪除一個(gè)元素

     

     

    hashtable.remove("one");

     

     

    // Iterator遍歷

     

     

    Iterator keyIt = hashtable.keySet().iterator();

     

     

    while (keyIt.hasNext()) {

     

     

    Object keyName = keyIt.next();

     

     

    String value = (String) hashtable.get(keyName);

     

     

    }

     

     

    Iterator valueIt = hashtable.values().iterator();

     

     

    while (valueIt.hasNext()) {

     

     

    valueIt.next();

     

     

    }

     

     

     

     

    // Enumeration遍歷, 只有Hashtable, HashMap沒有.

     

     

    Enumeration enu = hashtable.elements();

     

     

    while (enu.hasMoreElements()) {

     

     

    enu.nextElement();

     

     

    }

     

     

     

     

     

     

    說(shuō)明: Enumeration是老集合庫(kù)中的接口, Iterator是新集合(1.2)中出現(xiàn)的, VectorHashtable也都是老集合中的類, 所以只有VectorHashtable可以用Enumeration。

     

     

     

     

    VectorArrayList對(duì)比:

     

     

    雖然在使用的時(shí)候好象這兩個(gè)類沒什么區(qū)別, 它們都是從List繼承下來(lái)的, 擁有相同的方法, 但它們的內(nèi)部還是有些不同的,

    Ø         首先Vector在內(nèi)部的一些方法作了線程同步(synchronized)。 同步的代價(jià)就是降低了執(zhí)行效率, 但提高了安全性。而ArrayList則是線程不同步的, 可以多線程并發(fā)讀寫它。

    Ø         內(nèi)部數(shù)據(jù)增長(zhǎng)率。 所有的這些矢量集合在內(nèi)部都是用Object的數(shù)組進(jìn)行存儲(chǔ)和操作的。 所以也就明白了為什么它可以接受任何類型的Object 但取出來(lái)的時(shí)候需要進(jìn)行類型再造。 VectorArrayList具有自動(dòng)伸縮的功能, 我們不用管它size多大, 我們都可以在它的后面追加元素。 VectorArrayList內(nèi)部的數(shù)組增長(zhǎng)率是不一樣的, 當(dāng)內(nèi)部的數(shù)組不能容納更多元素的時(shí)候, Vector會(huì)自動(dòng)增長(zhǎng)到原兩倍大小, ArrayList會(huì)變?yōu)樵槐栋氪笮。?/span> 而不是我們所想象的一個(gè)元素一個(gè)元素的增長(zhǎng)。

     

     

    HashtableHashMap對(duì)比:

     

     

    HashtableHashMap都是從Map繼承下來(lái)的, 方法幾乎都一樣, 它們內(nèi)部有兩個(gè)不同點(diǎn):

    Ø         VectorArrayList一樣, 它們?cè)诰€程同步是不同的, Hashtable在內(nèi)部做了線程同步, HashMap是線程不同步的。

    Ø         HashMap的鍵與值都可以為null, Hashtable不可以, 如果你試圖將一個(gè)null值放到Hashtable里面去, 會(huì)拋一個(gè)NullPointException的。

     

     

    性能對(duì)比:

     

     

    拋開不常用的集合不講, 每種集合都應(yīng)該有一個(gè)我們常用的集合類, 而在不同的場(chǎng)合下應(yīng)該使用效率最高的一個(gè)。 一般來(lái)說(shuō)我推薦盡量使用新的集合類, 除非不得已, 比如說(shuō)需要用用了老集合類寫的產(chǎn)品的程序。 也就是說(shuō)盡量使用ArrayListHashMap, 而少使用VectorHashtable。

    Ø         在單線程中使用ArrayListHashMap, 而在多線程中如果需要進(jìn)行線程同步可以使用VectorHashtable, 但也可以用synchronized對(duì)ArrayListHashMap進(jìn)行同步, 不過(guò)同步后的ArrayListHashMap是比VectorHashtable慢的。 不過(guò)我認(rèn)為需要進(jìn)行線程同步的地方并不多。 如果一個(gè)變量定義在方法內(nèi)部同時(shí)只可能有一個(gè)線程對(duì)之進(jìn)行操作, 就不必要進(jìn)行同步, 如果定義在類的內(nèi)部并且不是靜態(tài)的, 屬于實(shí)例變量, 而這個(gè)類并沒有被多線程使用也就不必要同步。
    一般自己寫的程序很少會(huì)自己去另開線程的, 但在Web開發(fā)的時(shí)候, 如果用了Servlet, 則每個(gè)request都是一個(gè)線程, 也就是說(shuō)每個(gè)Servlet都是在多線程環(huán)境下運(yùn)行的, 如果Servlet中使用了全局靜態(tài)的成員變量就得小心點(diǎn)兒, 如果需要同步就得在方法上加上synchronized修飾符, 如果允許多個(gè)線程操作它, 并且你知道不會(huì)有什么沖突問題就可以大膽的使用ArrayListHashMap。 另外如果在多線程中有線程在對(duì)ArrayListHashMap進(jìn)行修改(結(jié)構(gòu)上的修改), 而有一個(gè)線程在用Iterator進(jìn)行讀取操作, 這個(gè)時(shí)候就有可能會(huì)拋ConcurrentModificationException, 因?yàn)橛?/span>Iterator的時(shí)候, 不允許原List的結(jié)構(gòu)改變。但可以用get方法來(lái)取。

     

     

    常用技巧:

     

     

    1.         采用面向接口的編程技巧, 比如現(xiàn)在需要寫一個(gè)共通函數(shù),對(duì)矢量集合類諸如Vector,ArrayList,HashSet等等進(jìn)行操作, 但我并不知道最終用戶會(huì)具體傳給我什么類型的類, 這個(gè)時(shí)候我們可以使用Collection接口, 從而使代碼具有很大的靈活性。 代碼示例如下:

    /**

     

     

     * list里面的所有元素用sep連接起來(lái),

     

     

     * list可以為Vector, ArrayList, HashSet等。

     

     

     */

    public static String join(String sep, Collection list) {

     

     

       StringBuffer sb = new StringBuffer();

     

     

       Iterator iterator = list.iterator();

     

     

      

       while (iterator.hasNext()) {

     

     

              sb.append(iterator.next());

     

     

              if (iterator.hasNext()) {

     

     

                     sb.append(sep);

     

     

              }

     

     

       }

     

     

      

       return sb.toString();

     

     

    }

     

     

     

     

    2.         利用Set進(jìn)行Unique, 比如有一組對(duì)象(其中有對(duì)象是重復(fù)的), 但我們只對(duì)不同的對(duì)象感興趣, 這個(gè)時(shí)候可以使用HashSet這個(gè)集合類, 然后可以通過(guò)覆蓋Objectequals方法來(lái)選擇自定義判斷相等的rule 缺省的是地址判斷。 例:

     

     

    class DataClass {

     

     

       private String code = null;

     

     

       private String name = null;

     

     

      

     

     

       public void setCode(String code) {

     

     

              this.code = code;

     

     

       }

     

     

       public String getCode() {

     

     

              return this.code;

     

     

       }

     

     

      

     

     

       public void setName(String name) {

     

     

              this.name = name;

     

     

       }

     

     

       public String getName() {

     

     

              return this.name;

     

     

       }

     

     

      

     

     

       public boolean equals(DataClass otherData) {

     

     

              if (otherData != null) {

     

     

                     if (this.getCode() != null

     

     

                                   && this.getCode().equals(otherData.getCode()) {

     

     

                            return true;

     

     

                     }

     

     

              }

     

     

              return false;

     

     

       }

     

     

    }

     

     

     

     

    DataClass data1 = new DataClass();

     

     

    DataClass data2 = new DataClass();

     

     

    data1.setCode("1");

     

     

    data2.setCode("1");

     

     

     

     

    HashSet singleSet = new HashSet();

     

     

    singleSet.add(data1);

     

     

    singleSet.add(data2);

     

     

    結(jié)果singleSet里面只有data1, 因?yàn)?/span>data2.equals(data1), 所以data2并沒有加進(jìn)去。

     

     

    3.         靈活的設(shè)計(jì)集合的存儲(chǔ)方式, 以獲得較高效的處理。 集合里面可以再嵌套集合, 例:在ArrayList里面存放HashMap, HashMap里面再嵌套HashMap。

     

     

    8ResourceBundle, Properties

     

    ResourceBundle開發(fā)一個(gè)項(xiàng)目, 配置文件是少不了的, 一些需要根據(jù)環(huán)境進(jìn)行修改的參數(shù), 都有得放到配置文件中去, Java中一般是通過(guò)一個(gè)properties文件來(lái)實(shí)現(xiàn)的, 這個(gè)文件以properties結(jié)尾。 內(nèi)部結(jié)構(gòu)是二維的, key=value的形式存在。 如下:

    options.column.name.case=1

    options.column.bean.serializable=1

    options.column.bean.defaultconstructor=1

    options.column.method.setter=1

    options.general.user.version=1.0

    database.connection[0]=csc/csc@localhost_oci8

    database.connection[1]=cscweb/cscweb@localhost_thin

     

     

    ResourceBundle用來(lái)解析這樣的文件, 它的功能是可以根據(jù)你的Locale來(lái)進(jìn)行解析配置文件, 如果一個(gè)產(chǎn)品需要進(jìn)行多語(yǔ)言支持, 比如在不同語(yǔ)種的系統(tǒng)上, 會(huì)顯示根據(jù)它的語(yǔ)言顯示相應(yīng)的界面語(yǔ)言, 就可以定義多份的properties文件, 每個(gè)文件的key是一樣的, 只是value不一樣, 然后在application起動(dòng)的時(shí)候, 可以判別本機(jī)的Locale來(lái)解析相應(yīng)的properties文件。 Properties文件里面的數(shù)據(jù)得要是Unicode jdk下面可以用native2ascii這個(gè)命令進(jìn)行轉(zhuǎn)換。 例: native2ascii Message.txt Message.properties 會(huì)生成一個(gè)Unicode的文件。

     

     

    Properties: Properties這個(gè)類其實(shí)就是從Hashtable繼承下來(lái)的, 也就是說(shuō)它是一個(gè)散列表, 區(qū)別在于它的keyvalue都是String型的, 另外也加了幾個(gè)常用的方法:

    Ø         String getProperty(String key) 取得一個(gè)property

    Ø         String getProperty(String key, String defaultValue)  property, 如果不存在則返回defaultValue

    Ø         void list(PrintStream out) out輸出所有的properties

    Ø         void list(PrintWriter out)

    Ø         Enumeration propertyNames() 將所有的property key名以Enumeration形式返回。

    Ø         Object setProperty(String key, String value) 設(shè)置一個(gè)property。

     

     

    ResourceBundleProperties一般結(jié)合起來(lái)使用。 它們的用法很簡(jiǎn)單, ResourceBundle解析出來(lái)的keyvalue然后放至到一個(gè)靜態(tài)的Properties成員變量里面去, 然后就可以通過(guò)訪問Properties的方法進(jìn)行讀取Property。 下面給個(gè)簡(jiǎn)單的例子:

    public class PropertyManager implements Serializable {

     

     

     

     

    /** 定義一個(gè)靜態(tài)的Properties變量 */

     

     

    private static Properties properties = new Properties();

     

     

     

     

    /**

     

     

     * 通過(guò)一個(gè)類似于類名的參數(shù)進(jìn)行Property文件的初期化

     

     

     * 比如現(xiàn)在有一個(gè)文件叫Message.properties, 它存放在

     

     

     * ejb/util下面并且, 這個(gè)目錄在運(yùn)行的classpath下面

     

     

     * in就為ejb.util.Message

     

     

     *

     

     

     */

     

     

    public static void init(String in) throws MissingResourceException {

     

     

        ResourceBundle bundle = ResourceBundle.getBundle(in);

     

     

        Enumeration enum = bundle.getKeys();

     

     

        Object key = null;

     

     

        Object value = null;

     

     

        while (enum.hasMoreElements()) {

     

     

            key = enum.nextElement();

     

     

            value = bundle.getString(key.toString());

     

     

            properties.put(key, value);

     

     

        }

     

     

    }

     

     

     

     

    /**

     

     

     * 取得一個(gè)Property

     

     

     */

     

     

    public static String getProperty(String key) {

     

     

            return properties.get(key);

     

     

    }

     

     

     

     

    /**

     

     

     * 設(shè)置一個(gè)Property

     

     

     */

     

     

    public static void setProperty(String key, String value) {

     

     

            properties.put(key, value);

     

     

    }

     

     

    }

     

     

     

     

    不過(guò)現(xiàn)在的Java產(chǎn)品中,越來(lái)越傾向于用XML替換Properties文件來(lái)進(jìn)行配置。 XML配置具有層次結(jié)構(gòu)清楚的優(yōu)點(diǎn)。

     

     

    9. Exceptions

    Throwable

    Exception

    Error

    RuntimeException

    ClassNotFoundException

    IOException

    SQLException

    IndexOutOfBoundsException

    ClassCastException

    NullPointerException

    OutOfMemoryError

    StackOverflowError

    NoClassDefFoundError

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     


    Java采用違例(Exception)處理機(jī)制來(lái)進(jìn)行錯(cuò)誤處理。 違例機(jī)制的一個(gè)好處就是能夠簡(jiǎn)化錯(cuò)誤控制代碼, 我們?cè)僖膊挥脵z查一個(gè)特定的錯(cuò)誤, 然后在程序的多處地方對(duì)其進(jìn)行控制。 此外, 也不需要在方法調(diào)用的時(shí)候檢查錯(cuò)誤(因?yàn)楸WC有人能夠捕獲這里的錯(cuò)誤)。 我們只需要在一個(gè)地方處理問題:違例控制模塊或者違例控制器 這樣可有效減少代碼量, 并將那些用于描述具體操作的代碼與專門糾正錯(cuò)誤的代碼分隔開。

     

     

    一個(gè)完整的違例例子:

    public void throwTest() throws MyException {

     

     

    try {

     

     

            ...

     

     

    } catch (SQLException se) {

     

     

            cat.error("", se);

     

     

            throw new MyException(se.getMessage());

     

     

    } catch (Exception e) {

     

     

            cat.error("", e);

     

     

    } finally {

     

     

            ...

     

     

    }

     

     

    }

     

     

     

     

    如果一段代碼有可能會(huì)拋出違例可以用try {} catch {}來(lái)處理。 catch到的違例可以再拋出, 也可以轉(zhuǎn)換為其它類型的Exception拋出。 finally塊里面的代碼總會(huì)被執(zhí)行到的, 不管前面是否已經(jīng)throwreturn了。

     

     

    Throwable是所有違例的基類, 它有兩種常規(guī)類型。 其中, Error代表編繹期和系統(tǒng)錯(cuò)誤, 我們一般不必特意捕獲它們。 Exception是可以從任何標(biāo)準(zhǔn)Java庫(kù)的類方法中擲出的基本類型。

     

     

    看上面的圖, 如果是Error的子類或是RuntimeException的子類這種違例有一定的特殊性, 可以說(shuō)我們可以當(dāng)它們不存在, 當(dāng)這種違例拋出的時(shí)候, 我們可以不catch它, 也可以不在方法上throws它。 RuntimeException一般代表的是一個(gè)編程錯(cuò)誤, 是完全可以避免的。

     

     

    性能注意點(diǎn): 因?yàn)槭褂昧?/span>Exception之后是要影響一些效率的, 所以Exception不能濫用。一般的不要用Exception來(lái)控制業(yè)務(wù)流程, 其次不要循環(huán)體內(nèi)使用。

     

     

    技巧:我們可以從Exception或直接從Throwable繼承寫我們自己的Exception 然后根據(jù)業(yè)務(wù)需要拋不同種類的Exception。

    10. JDBC類庫(kù)

     

    有了 JDBC,向各種關(guān)系數(shù)據(jù)庫(kù)發(fā)送 SQL 語(yǔ)句就是一件很容易的事。換言之,有了 JDBC API,就不必為訪問 Sybase 數(shù)據(jù)庫(kù)專門寫一個(gè)程序,為訪問 Oracle 數(shù)據(jù)庫(kù)又專門寫一個(gè)程序,為訪問 Informix 數(shù)據(jù)庫(kù)又寫另一個(gè)程序,等等。您只需用 JDBC API 寫一個(gè)程序就夠了,它可向相應(yīng)數(shù)據(jù)庫(kù)發(fā)送 SQL 語(yǔ)句。而且,使用 Java 編程語(yǔ)言編寫的應(yīng)用程序,就無(wú)須去憂慮要為不同的平臺(tái)編寫不同的應(yīng)用程序。將 Java JDBC 結(jié)合起來(lái)將使程序員只須寫一遍程序就可讓它在任何平臺(tái)上運(yùn)行。

     

     

    下面為常用的處理流程:

     

     

     

     

     

     

    DriverManager

     

     

     

     

     

     

     

     

     

     

    Connection

     

     

     

     

     

     

     

     

     

     

     

     

    Statement

    PreparedStatement

    CallableStatement

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    ResultSet

     

     

     

     

     

     

     

     


    簡(jiǎn)單地說(shuō),JDBC 可做三件事:

     

     

    1.         與數(shù)據(jù)庫(kù)建立連接

    2.         發(fā)送 SQL 語(yǔ)句

    3.         處理結(jié)果

     

     

    下列代碼段給出了以上三步的基本示例:

     

     

    Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();

     

     

    Connection conn = DriverManager.getConnection (

     

     

    "jdbc:oracle:thin:@eai-sol:1521:eai_db", "csc2", "csc2");

     

     

    Statement stmt = conn.createStatement();

     

     

    ResultSet rs = stmt.executeQuery("SELECT CONTACTID FROM CONTACTINFO");

     

     

    while (rs.next()) {

     

     

    long contactID = rs.getLong("CONTACTID");

     

     

    }

     

     

     

     

    下面對(duì)常用的幾個(gè)類和接口做些簡(jiǎn)單的說(shuō)明。

     

     

    DriverManager:

     

     

    DriverManager類是 JDBC 的管理層,作用于用戶和驅(qū)動(dòng)程序之間。它跟蹤可用的驅(qū)動(dòng)程序,并在數(shù)據(jù)庫(kù)和相應(yīng)驅(qū)動(dòng)程序之間建立連接。另外,DriverManager 類也處理諸如驅(qū)動(dòng)程序登錄時(shí)間限制及登錄和跟蹤消息的顯示等事務(wù)。對(duì)于簡(jiǎn)單的應(yīng)用程序,一般程序員需要在此類中直接使用的唯一方法是 DriverManager.getConnection。正如名稱所示,該方法將建立與數(shù)據(jù)庫(kù)的連接。

     

     

    Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();

     

     

    Connection conn = DriverManager.getConnection (

     

     

    "jdbc:oracle:thin:@eai-sol:1521:eai_db", "csc2", "csc2");

     

     

    其中第一句話的作用是在當(dāng)前的環(huán)境中load一個(gè)DB Driver, 有人可能覺得奇怪, 這句話執(zhí)行完之后, 后面怎么知道去用這個(gè)Driver呢? 其實(shí)DriverManager可以從loadclasses里面找到注冊(cè)過(guò)的driver,然后使用它所找到的第一個(gè)可以成功連接到給定 URL 的驅(qū)動(dòng)程序。 第二句話的三個(gè)參數(shù)分別是URL, User, Password。Driver不一樣, URL可能也不一樣。

     

     

     

     

    Statement:

     

     

    Statement 對(duì)象用于將 SQL 語(yǔ)句發(fā)送到數(shù)據(jù)庫(kù)中。實(shí)際上有三種 Statement 對(duì)象,它們都為在給定連接上執(zhí)行 SQL 語(yǔ)句的包容器:Statement、PreparedStatement(它從 Statement 承而來(lái))和 CallableStatement(它從 PreparedStatement 繼承而來(lái))。它們都專用于發(fā)送定類型的 SQL 語(yǔ)句: Statement 對(duì)象用于執(zhí)行不帶參數(shù)的簡(jiǎn)單 SQL 語(yǔ)句;PreparedStatement 對(duì)象用于執(zhí)行帶或不帶 IN 參數(shù)的預(yù)編譯 SQL 語(yǔ)句;CallableStatement 對(duì)象用于執(zhí)行對(duì)數(shù)據(jù)庫(kù)已存儲(chǔ)過(guò)程的調(diào)用。

     

     

    Statement 接口提供了執(zhí)行語(yǔ)句和獲取結(jié)果的基本方法。PreparedStatement 接口添加了處理 IN 參數(shù)的方法;而 CallableStatement 添加了處理 OUT 參數(shù)的方法。

     

     

    Ø         創(chuàng)建 Statement 對(duì)象
    建立了到特定數(shù)據(jù)庫(kù)的連接之后,就可用該連接發(fā)送 SQL 語(yǔ)句。Statement 對(duì)象用 Connection 的方法 createStatement 創(chuàng)建,如下列代碼段中所示:
    Statement stmt = conn.createStatement();

    為了執(zhí)行 Statement 對(duì)象,被發(fā)送到數(shù)據(jù)庫(kù)的 SQL 語(yǔ)句將被作為參數(shù)提供給 Statement 的方法:
    ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM table1");

     

     

     

     

    Ø         使用 Statement 對(duì)象執(zhí)行語(yǔ)句

     

     

    Statement 接口提供了三種執(zhí)行 SQL 語(yǔ)句的方法:executeQuery、executeUpdate execute。使用哪一個(gè)方法由 SQL 語(yǔ)句所產(chǎn)生的內(nèi)容決定。
    方法 executeQuery 用于產(chǎn)生單個(gè)結(jié)果集的語(yǔ)句,例如 SELECT 語(yǔ)句。

     

     

    方法 executeUpdate 用于執(zhí)行 INSERTUPDATE DELETE 語(yǔ)句以及 SQL DDL(數(shù)據(jù)定義語(yǔ)言)語(yǔ)句,例如 CREATE TABLE DROP TABLE。INSERTUPDATE DELETE 語(yǔ)句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一個(gè)整數(shù),指示受影響的行數(shù)(即更新計(jì)數(shù))。對(duì)于 CREATE TABLE DROP TABLE 等不操作行的語(yǔ)句,executeUpdate 的返回值總為零。

     

     

    方法 execute 用于執(zhí)行返回多個(gè)結(jié)果集、多個(gè)更新計(jì)數(shù)或二者組合的語(yǔ)句。

     

     

     

     

    Ø         語(yǔ)句完成

     

     

    當(dāng)連接處于自動(dòng)提交模式時(shí),其中所執(zhí)行的語(yǔ)句在完成時(shí)將自動(dòng)提交或還原。語(yǔ)句在已執(zhí)行且所有結(jié)果返回時(shí),即認(rèn)為已完成。對(duì)于返回一個(gè)結(jié)果集的 executeQuery 方法,在檢索完 ResultSet 對(duì)象的所有行時(shí)該語(yǔ)句完成。對(duì)于方法 executeUpdate,當(dāng)它執(zhí)行時(shí)語(yǔ)句即完成。但在少數(shù)調(diào)用方法 execute 的情況中,在檢索所有結(jié)果集或它生成的更新計(jì)數(shù)之后語(yǔ)句才完成。

     

     

     

     

    Ø         關(guān)閉 Statement 對(duì)象

    Statement 對(duì)象將由 Java 垃圾收集程序自動(dòng)關(guān)閉。而作為一種好的編程風(fēng)格,應(yīng)在不需要 Statement 對(duì)象時(shí)顯式地關(guān)閉它們。這將立即釋放 DBMS 資源,有助于避免潛在的內(nèi)存問題。 關(guān)閉Statement stmt.close() 方法。

     

     

    ResultSet:

     

     

    ResultSet 包含符合 SQL 語(yǔ)句中條件的所有行,并且它通過(guò)一套 get 方法(這些 get 方法可以訪問當(dāng)前行中的不同列)提供了對(duì)這些行中數(shù)據(jù)的訪問。ResultSet.next 方法用于移動(dòng)到 ResultSet 中的下一行,使下一行成為當(dāng)前行。

     

     

    結(jié)果集一般是一個(gè)表,其中有查詢所返回的列標(biāo)題及相應(yīng)的值。例如,如果查詢?yōu)?span> SELECT a, b, c FROM Table1,則結(jié)果集將具有如下形式:

     

     

    a        b         c

     

     

    -------- --------- --------

     

     

    12345    Cupertino CA

     

     

    83472    Redmond   WA

     

     

    83492    Boston    MA
    下面的代碼段是執(zhí)行 SQL 語(yǔ)句的示例。該 SQL 語(yǔ)句將返回行集合,其中列 1 int,列 2 String,而列 3 則為日期型:

     

     

    Statement stmt = conn.createStatement();

     

     

    ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");

     

     

    while (rs.next()) {

     

     

    int i = rs.getInt("a");

     

     

    String s = rs.getString("b");

     

     

    Timestamp t = rs.getTimestamp("c");

     

     

    }

     

     

     

     

    Ø         行和光標(biāo)

     

     

    ResultSet 維護(hù)指向其當(dāng)前數(shù)據(jù)行的光標(biāo)。每調(diào)用一次 next 方法,光標(biāo)向下移動(dòng)一行。最初它位于第一行之前,因此第一次調(diào)用 next 將把光標(biāo)置于第一行上,使它成為當(dāng)前行。隨著每次調(diào)用 next 導(dǎo)致光標(biāo)向下移動(dòng)一行,按照從上至下的次序獲取 ResultSet 行。在 ResultSet 對(duì)象或其父輩 Statement 對(duì)象關(guān)閉之前,光標(biāo)一直保持有效。

     

     

     

     

    Ø        

     

     

    方法 getXXX 提供了獲取當(dāng)前行中某列值的途徑。在每一行內(nèi),可按任何次序獲取列值。但為了保證可移植性,應(yīng)該從左至右獲取列值,并且一次性地讀取列值。列名或列號(hào)可用于標(biāo)識(shí)要從中獲取數(shù)據(jù)的列。例如,如果 ResultSet 對(duì)象 rs 的第二列名為“title”,并將值存儲(chǔ)為字符串,則下列任一代碼將獲取存儲(chǔ)在該列中的值:

     

     

     

     

    String s = rs.getString("title");

     

     

    String s = rs.getString(2);

     

     

     

     

    注意列是從左至右編號(hào)的,并且從列 1 開始。同時(shí),用作 getXXX 方法的輸入的列名不區(qū)分大小寫。 為了代碼的可維護(hù)性與可讀性, 應(yīng)該禁止用index的方法來(lái)取值, 要用讀列名的方法, 如上面的第一行取值方法。

     

     

     

     

    Ø         數(shù)據(jù)類型和轉(zhuǎn)換

     

     

    對(duì)于 getXXX 方法,JDBC 驅(qū)動(dòng)程序試圖將基本數(shù)據(jù)轉(zhuǎn)換成指定 Java 類型,然后返回適合的 Java 值。例如,如果 getXXX 方法為 getString,而基本數(shù)據(jù)庫(kù)中數(shù)據(jù)類型為 VARCHAR,則 JDBC 驅(qū)動(dòng)程序?qū)?span> VARCHAR 轉(zhuǎn)換成 Java String。getString 的返回值將為 Java String 對(duì)象。

     

     

     

     

    Ø         NULL 結(jié)果值

     

     

    要確定給定結(jié)果值是否是 JDBC NULL,必須先讀取該列,然后使用 ResultSet.wasNull 方法檢查該次讀取是否返回 JDBC NULL。

     

     

     

     

    PreparedStatement:

     

     

    PreparedStatement 接口繼承 Statement,并與之在兩方面有所不同:

     

     

    PreparedStatement 實(shí)例包含已編譯的 SQL 語(yǔ)句。這就是使語(yǔ)句“準(zhǔn)備好”。 包含于 PreparedStatement 對(duì)象中的 SQL 語(yǔ)句可具有一個(gè)或多個(gè) IN 參數(shù)。IN 參數(shù)的值在 SQL 語(yǔ)句創(chuàng)建時(shí)未被指定。相反的,該語(yǔ)句為每個(gè) IN 參數(shù)保留一個(gè)問號(hào)(“?”)作為占位符。每個(gè)問號(hào)的值必須在該語(yǔ)句執(zhí)行之前,通過(guò)適當(dāng)?shù)?span> setXXX 方法來(lái)提供。

     

     

    由于 PreparedStatement 對(duì)象已預(yù)編譯過(guò),所以其執(zhí)行速度要快于 Statement 對(duì)象。因此,多次執(zhí)行的 SQL 語(yǔ)句經(jīng)常創(chuàng)建為 PreparedStatement 對(duì)象,以提高效率。

     

     

    作為 Statement 的子類,PreparedStatement 繼承了 Statement 的所有功能。另外它還添加了一整套方法,用于設(shè)置發(fā)送給數(shù)據(jù)庫(kù)以取代 IN 參數(shù)占位符的值。同時(shí),三種方法 execute executeQuery executeUpdate 已被更改以使之不再需要參數(shù)。

     

     

     

     

    Ø         創(chuàng)建 PreparedStatement 對(duì)象

     

     

    以下的代碼段(其中 conn Connection 對(duì)象)創(chuàng)建包含帶兩個(gè) IN 參數(shù)占位符的 SQL 語(yǔ)句的 PreparedStatement 對(duì)象:

     

     

     

     

    PreparedStatement pstmt =

     

     

    conn.prepareStatement("UPDATE table1 SET a = ? WHERE b = ?");

     

     

     

     

    pstmt 對(duì)象包含語(yǔ)句 " UPDATE table1 SET a = ? WHERE b = ?",它已發(fā)送給 DBMS,并為執(zhí)行作好了準(zhǔn)備。

     

     

     

     

    Ø         傳遞 IN 參數(shù)

     

     

    在執(zhí)行 PreparedStatement 對(duì)象之前,必須設(shè)置每個(gè) ? 參數(shù)的值。這可通過(guò)調(diào)用 setXXX 方法來(lái)完成,其中 XXX 是與該參數(shù)相應(yīng)的類型。例如,如果參數(shù)具有 Java 類型 long,則使用的方法就是 setLongsetXXX 方法的第一個(gè)參數(shù)是要設(shè)置的參數(shù)的序數(shù)位置,第二個(gè)參數(shù)是設(shè)置給該參數(shù)的值。例如,以下代碼將第一個(gè)參數(shù)設(shè)為 123456789,第二個(gè)參數(shù)設(shè)為 100000000

     

     

    pstmt.setLong(1, 123456789);

     

     

    pstmt.setLong(2, 100000000);

     

     

     

     

    CallableStatement:

     

     

    CallableStatement 對(duì)象為所有的 DBMS 提供了一種以標(biāo)準(zhǔn)形式調(diào)用已儲(chǔ)存過(guò)程(也就是SP)的方法。已儲(chǔ)存過(guò)程儲(chǔ)存在數(shù)據(jù)庫(kù)中。對(duì)已儲(chǔ)存過(guò)程的調(diào)用是 CallableStatement 對(duì)象所含的內(nèi)容。有兩種形式:一種形式帶結(jié)果參數(shù),另一種形式不帶結(jié)果參數(shù)。結(jié)果參數(shù)是一種輸出 (OUT) 參數(shù),是已儲(chǔ)存過(guò)程的返回值。兩種形式都可帶有數(shù)量可變的輸入(IN 參數(shù))、輸出(OUT 參數(shù))或輸入和輸出(INOUT 參數(shù))的參數(shù)。問號(hào)將用作參數(shù)的占位符。

     

     

     

     

    JDBC 中調(diào)用已儲(chǔ)存過(guò)程的語(yǔ)法如下所示。注意,方括號(hào)表示其間的內(nèi)容是可選項(xiàng);方括號(hào)本身并不是語(yǔ)法的組成部份。

     

     

     

     

    {call 過(guò)程名[(?, ?, ...)]}

     

     

     

     

    返回結(jié)果參數(shù)的過(guò)程的語(yǔ)法為:

     

     

     

     

    {? = call 過(guò)程名[(?, ?, ...)]}

     

     

     

     

    不帶參數(shù)的已儲(chǔ)存過(guò)程的語(yǔ)法類似:

     

     

     

     

    {call 過(guò)程名}

     

     

     

     

    通常,創(chuàng)建 CallableStatement 對(duì)象的人應(yīng)當(dāng)知道所用的 DBMS 是支持已儲(chǔ)存過(guò)程的,并且知道這些過(guò)程都是些什么。然而,如果需要檢查,多種 DatabaseMetaData 方法都可以提供這樣的信息。例如,如果 DBMS 支持已儲(chǔ)存過(guò)程的調(diào)用,則 supportsStoredProcedures 方法將返回 true,而 getProcedures 方法將返回對(duì)已儲(chǔ)存過(guò)程的描述。

     

     

     

     

    CallableStatement 繼承 Statement 的方法(它們用于處理一般的 SQL 語(yǔ)句),還繼承了 PreparedStatement 的方法(它們用于處理 IN 參數(shù))。CallableStatement 中定義的所有方法都用于處理 OUT 參數(shù)或 INOUT 參數(shù)的輸出部分:注冊(cè) OUT 參數(shù)的 JDBC 類型(一般 SQL 類型)、從這些參數(shù)中檢索結(jié)果,或者檢查所返回的值是否為 JDBC NULL

     

     

     

     

    Ø         創(chuàng)建 CallableStatement 對(duì)象

     

     

    CallableStatement 對(duì)象是用 Connection 方法 prepareCall 創(chuàng)建的。下例創(chuàng)建 CallableStatement 的實(shí)例,其中含有對(duì)已儲(chǔ)存過(guò)程 Csc_ GetCustomId調(diào)用。該過(guò)程有兩個(gè)變量,但不含結(jié)果參數(shù):

     

     

     

     

    CallableStatement cstmt = con.prepareCall(

     

     

    "{call CSC_GetCustomId (?, ?, ?)}");

     

     

     

     

    其中 ? 占位符為 IN、 OUT 還是 INOUT 參數(shù),取決于已儲(chǔ)存過(guò)程 Csc_ GetCustomId

     

     

     

     

    Ø         IN OUT 參數(shù)

     

     

    IN 參數(shù)傳給 CallableStatement 對(duì)象是通過(guò) setXXX 方法完成的。該方法繼承自 PreparedStatement。所傳入?yún)?shù)的類型決定了所用的 setXXX 方法(例如,用 setFloat 來(lái)傳入 float 值等)。

     

     

    如果已儲(chǔ)存過(guò)程返回 OUT 參數(shù),則在執(zhí)行 CallableStatement 對(duì)象以前必須先注冊(cè)每個(gè) OUT 參數(shù)的 JDBC 類型(這是必需的,因?yàn)槟承?span> DBMS 要求 JDBC 類型)。注冊(cè) JDBC 類型是用 registerOutParameter 方法來(lái)完成的。語(yǔ)句執(zhí)行完后,CallableStatement getXXX 方法將取回參數(shù)值。正確的 getXXX 方法是為各參數(shù)所注冊(cè)的 JDBC 類型所對(duì)應(yīng)的 Java 類型也就是說(shuō), registerOutParameter 使用的是 JDBC 類型(因此它與數(shù)據(jù)庫(kù)返回的 JDBC 類型匹配),而 getXXX 將之轉(zhuǎn)換為 Java 類型。下面給出CSC中的一個(gè)例子:

     

     

    String sqlSp = "{call CSC_GetCustomId(?, ?, ?)}";

     

     

    cstmt = conn.prepareCall(sqlSp.toString());

     

     

    cstmt.registerOutParameter(1, Types.NUMERIC);

     

     

    cstmt.registerOutParameter(2, Types.NUMERIC);

     

     

    cstmt.registerOutParameter(3, Types.VARCHAR);

     

     

    cstmt.execute();

     

     

    long customerID = cstmt.getLong(1);

     

     

    long lRet = cstmt.getLong(2);

     

     

    String sErr = cstmt.getString(3);

     

     

     

     

    Ø         INOUT 參數(shù)

     

     

    既支持輸入又接受輸出的參數(shù)(INOUT 參數(shù))除了調(diào)用 registerOutParameter 方法外,還要求調(diào)用適當(dāng)?shù)?span> setXXX 方法(該方法是從 PreparedStatement 繼承來(lái)的)。setXXX 方法將參數(shù)值設(shè)置為輸入?yún)?shù),而 registerOutParameter 方法將它的 JDBC 類型注冊(cè)為輸出參數(shù)。setXXX 方法提供一個(gè) Java 值,而驅(qū)動(dòng)程序先把這個(gè)值轉(zhuǎn)換為 JDBC 值,然后將它送到數(shù)據(jù)庫(kù)中。這種 IN 值的 JDBC 類型和提供給 registerOutParameter 方法的 JDBC 類型應(yīng)該相同。然后,要檢索輸出值,就要用對(duì)應(yīng)的 getXXX 方法。例如,Java 類型為 byte 的參數(shù)應(yīng)該使用方法 setByte 來(lái)賦輸入值。應(yīng)該給 registerOutParameter 提供類型為 TINYINT JDBC 類型,同時(shí)應(yīng)使用 getByte 來(lái)檢索輸出值。下例假設(shè)有一個(gè)已儲(chǔ)存過(guò)程 reviseTotal,其唯一參數(shù)是 INOUT 參數(shù)。方法 setByte 把此參數(shù)設(shè)為 25,驅(qū)動(dòng)程序?qū)阉鳛?span> JDBC TINYINT 類型送到數(shù)據(jù)庫(kù)中。接著,registerOutParameter 將該參數(shù)注冊(cè)為 JDBC TINYINT。執(zhí)行完該已儲(chǔ)存過(guò)程后,將返回一個(gè)新的 JDBC TINYINT 值。方法 getByte 將把這個(gè)新值作為 Java byte 類型檢索。

     

     

    CallableStatement cstmt = con.prepareCall("{call reviseTotal(?)}");

     

     

    cstmt.setByte(1, 25);

     

     

    cstmt.registerOutParameter(1, java.sql.Types.TINYINT);

     

     

    cstmt.executeUpdate();

     

     

    byte x = cstmt.getByte(1);

     

     

     

     

     

     

    11. 常用設(shè)計(jì)模式

     

    1Singleton模式

     

     

    Singleton模式主要作用是保證在Java應(yīng)用程序中,一個(gè)Class只有一個(gè)實(shí)例存在。一般有兩種方法:

     

     

    Ø         定義一個(gè)類,它的構(gòu)造函數(shù)為private的,所有方法為static的。其他類對(duì)它的引用全部是通過(guò)類名直接引用。例如:

     

     

    private SingleClass() {}

     

     

    public static String getMethod1() {}

     

     

    public static ArrayList getMethod2() {}

     

     

    Ø         定義一個(gè)類,它的構(gòu)造函數(shù)為private的,它有一個(gè)staticprivate的該類變量,通過(guò)一個(gè)publicgetInstance方法獲取對(duì)它的引用,繼而調(diào)用其中的方法。例如:

     

     

    private staitc SingleClass _instance = null;

     

     

     

     

    private SingleClass() {}

     

     

     

     

    public static SingleClass getInstance() {

     

     

        if (_instance == null) {

     

     

             _instance = new SingleClass();

     

     

        }

     

     

        return _instance;

     

     

    }

     

     

     

     

    public String getMethod1() {}

     

     

    public ArrayList getMethod2() {}

     

     

     

     

    2Prototype模式

     

     

    Prototype模式用于創(chuàng)建對(duì)象,尤其是當(dāng)創(chuàng)建對(duì)象需要許多時(shí)間和資源時(shí)。在Java中,Prototype模式的實(shí)現(xiàn)是通過(guò)方法clone(),該方法定義在Java的根對(duì)象Object, 因此,Java中的其他對(duì)象只要覆蓋它就行了。通過(guò)clone(),我們可以從一個(gè)對(duì)象獲得更多的對(duì)象,

     

     

    并請(qǐng)可以按照我們的需要修改他們的屬性。

     

     

    public class Prototype implements Cloneable {

     

     

     

     

     private String Name;

     

     

     

     

     

     public Prototype(String Name) {

     

     

          this.Name = Name;

     

     

     }

     

     

     public void setName(String Name) {

     

     

          this.Name = Name;

     

     

     }

     

     

     public String getName() {

     

     

          return Name;

     

     

     }

     

     

     

     

     

     public Object clone() {

     

     

          try{

     

     

              return super.clone();

     

     

          }catch(CloneNotSupportedException cnse){

     

     

              cnse.printStackTrace();

     

     

              return null;

     

     

          }

     

     

     }

     

     

    }

     

     

     

     

    Prototype p = new Prototype("My First Name");

     

     

    Prototype p1 = p.clone();

     

     

    p.setName("My Second Name");

     

     

    Prototype p2 = p.clone();

     

     

     

     

    3. Factory模式和Abstract Factory模式

     

     

    Ø         Factory模式

     

     

    利用給Factory對(duì)象傳遞不同的參數(shù),以返回具有相同基類或?qū)崿F(xiàn)了同一接口的對(duì)象。

     

     

    Ø         Abstract Factory模式

     

     

    先利用Factory模式返回Factory對(duì)象,在通過(guò)Factory對(duì)象返回不同的對(duì)象!

     

     

     

     

    下面給出Sun XML Parser中的例子:

     

     

    // 1. Abstract Factory模式

     

     

    SAXParserFactory spf = SAXParserFactory.newInstance();

     

     

    String validation = System.getProperty (

     

     

    "javax.xml.parsers.validation", "false");

     

     

    if (validation.equalsIgnoreCase("true")) {

     

     

    spf.setValidating (true);

     

     

    }

     

     

     

     

    // 2. Factory模式

     

     

    SAXParser sp = spf.newSAXParser();

     

     

    parser = sp.getParser();

     

     

    parser.setDocumentHandler(this);

     

     

    parser.parse (uri);

     

     

     

     

    1. SAXParserFactory中的靜態(tài)方法newInstance()根據(jù)系統(tǒng)屬性javax.xml.parsers.SAXParserFactory不同的值生成不同的SAXParserFactory對(duì)象spf。然后SAXParserFactory對(duì)象又利用方法newSAXParser()生成SAXParser對(duì)象。

     

     

    注意:

     

     

    SAXParserFactory 的定義為:

     

     

    public abstract class SAXParserFactory extends java.lang.Object

     

     

    SAXParserFactoryImpl 的定義為:

     

     

    public class SAXParserFactoryImpl extends javax.xml.parsers.SAXParserFactory

     

     

     

     

    public static SAXParserFactory newInstance() {

     

     

    String factoryImplName = null;

     

     

     

     

    try {

     

     

         factoryImplName =

     

     

         System.getProperty("javax.xml.parsers.SAXParserFactory",

     

     

                 "com.sun.xml.parser.SAXParserFactoryImpl");

     

     

    } catch (SecurityException se) {

     

     

         factoryImplName = "com.sun.xml.parser.SAXParserFactoryImpl";

     

     

    }

     

     

     

     

    SAXParserFactory factoryImpl;

     

     

     

     

    try {

     

     

         Class clazz = Class.forName(factoryImplName);

     

     

         factoryImpl = (SAXParserFactory) clazz.newInstance();

     

     

    } catch (ClassNotFoundException cnfe) {

     

     

         throw new FactoryConfigurationError(cnfe);

     

     

    } catch (IllegalAccessException iae) {

     

     

         throw new FactoryConfigurationError(iae);

     

     

    } catch (InstantiationException ie) {

     

     

         throw new FactoryConfigurationError(ie);

     

     

    }

     

     

     

     

    return factoryImpl;

     

     

    }

     

     

     

     

     

     

    2. newSAXParser() 方法在SAXParserFactory定義為抽象方法,

     

     

    SAXParserFactoryImpl繼承了SAXParserFactory,它實(shí)現(xiàn)了方法newSAXParser()

     

     

    public SAXParser newSAXParser()

     

     

    throws SAXException, ParserConfigurationException {

     

     

    SAXParserImpl saxParserImpl = new SAXParserImpl(this);

     

     

    return saxParserImpl;

     

     

    }

     

     

     

     

    注意:

     

     

    SAXParserImpl的定義為:

     

     

    public class SAXParserImpl extends javax.xml.parsers.SAXParser

     

     

    SAXParserImpl的構(gòu)造函數(shù)定義為:

     

     

    public SAXParserImpl(SAXParserFactory spf)

     

     

    throws SAXException, ParserConfigurationException {

     

     

    super();

     

     

    this.spf = spf;

     

     

    if (spf.isValidating ()) {

     

     

         parser = new ValidatingParser();

     

     

         validating = true;

     

     

    } else {

     

     

         parser = new Parser();

     

     

    }

     

     

    if (spf.isNamespaceAware ()) {

     

     

         namespaceAware = true;

     

     

         throw new ParserConfigurationException(

     

     

    "Namespace not supported by SAXParser");

     

     

    }

     

     

    }

     

    posted on 2007-07-17 10:20 閱讀(1148) 評(píng)論(0)  編輯  收藏 所屬分類: java基礎(chǔ)
    主站蜘蛛池模板: 无遮挡免费一区二区三区| 亚洲国产精品综合久久网络| 亚洲一区二区三区不卡在线播放| 久久99国产乱子伦精品免费| 婷婷亚洲久悠悠色悠在线播放| 黄色网址在线免费| 亚洲国产精品无码中文字| 国产白丝无码免费视频| 亚洲国产精品久久| 91福利免费视频| 亚洲性色高清完整版在线观看| 999久久久免费精品国产| 国产91在线|亚洲| 国产精品免费观看久久| 亚洲免费综合色在线视频| 日韩免费电影在线观看| 污污视频网站免费观看| 亚洲午夜精品久久久久久浪潮| 久久国产精品免费一区| 国产v亚洲v天堂无码网站| 真实国产乱子伦精品免费| 亚洲最大黄色网址| 成年女人毛片免费播放人| 老司机亚洲精品影院在线观看| 国产一精品一aⅴ一免费| 四虎影视久久久免费| 奇米影视亚洲春色| 免费网站看av片| 亚洲大香伊人蕉在人依线| 成人免费无码视频在线网站| 337P日本欧洲亚洲大胆精品| 亚洲人成网站观看在线播放| 在线观看黄片免费入口不卡| 久久精品国产亚洲AV无码麻豆| 亚洲国产综合在线| 女人18毛片特级一级免费视频| 黄色a三级免费看| 国产精品亚洲аv无码播放| 99久久99久久免费精品小说| 亚洲熟女综合一区二区三区| 免费人成年轻人电影|