少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          #

          內部類是指在一個外部類的內部再定義一個類。內部類作為外部類的一個成員,并且依附于外部類而存在的。內部類可為靜態,可用protected和private修飾(而外部類只能使用public和缺省的包訪問權限)。內部類主要有以下幾類:成員內部類、局部內部類、靜態內部類、匿名內部類

            為什么需要內部類?

            典型的情況是,內部類繼承自某個類或實現某個接口,內部類的代碼操作創建其的外圍類的對象。所以你可以認為內部類提供了某種進入其外圍類的窗口。使用內部類最吸引人的原因是:

            每個內部類都能獨立地繼承自一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對于內部類都沒有影響。如果沒有內部類提供的可以繼承多個具體的或抽象的類的能力,一些設計與編程問題就很難解決。從這個角度看,內部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內部類有效地實現了“多重繼承”。

            A:成員內部類

            作為外部類的一個成員存在,與外部類的屬性、方法并列。

          publicclass Outer {
          privatestaticinti = 1;
          privateintj = 10;
          privateintk = 20;

          publicstaticvoidouter_f1() {
          }

          publicvoidouter_f2() {
          }

          // 成員內部類中,不能定義靜態成員
          // 成員內部類中,可以訪問外部類的所有成員
          class Inner {
          // static int inner_i = 100; //內部類中不允許定義靜態變量
          intj = 100; // 內部類和外部類的實例變量可以共存
          intinner_i = 1;

          void inner_f1() {
          System.out.println(i);
          //在內部類中訪問內部類自己的變量直接用變量名
          System.out.println(j);
          //在內部類中訪問內部類自己的變量也可以用this.變量名
          System.out.println(this.j);
          //在內部類中訪問外部類中與內部類同名的實例變量用外部類名.this.變量名
          System.out.println(Outer.this.j);
          //如果內部類中沒有與外部類同名的變量,則可以直接用變量名訪問外部類變量
          System.out.println(k);
          outer_f1();
          outer_f2();
          }
          }

          //外部類的非靜態方法訪問成員內部類
          publicvoidouter_f3() {
          Inner inner = new Inner();
          inner.inner_f1();
          }

          // 外部類的靜態方法訪問成員內部類,與在外部類外部訪問成員內部類一樣
          publicstaticvoidouter_f4() {
          //step1 建立外部類對象
          Outer out = new Outer();
          //step2 根據外部類對象建立內部類對象
          Inner inner = out.new Inner();
          //step3 訪問內部類的方法
          inner.inner_f1();
          }

          publicstaticvoid main(String[] args) {
          //outer_f4(); //該語句的輸出結果和下面三條語句的輸出結果一樣
          //如果要直接創建內部類的對象,不能想當然地認為只需加上外圍類Outer的名字,
          //就可以按照通常的樣子生成內部類的對象,而是必須使用此外圍類的一個對象來
          //創建其內部類的一個對象:
          //Outer.Inner outin = out.new Inner()
          //因此,除非你已經有了外圍類的一個對象,否則不可能生成內部類的對象。因為此
          //內部類的對象會悄悄地鏈接到創建它的外圍類的對象。如果你用的是靜態的內部類,
          //那就不需要對其外圍類對象的引用。
          Outer out = new Outer();
          Outer.Inner outin = out.new Inner();
          outin.inner_f1();
          }
          }

            注意:內部類是一個編譯時的概念,一旦編譯成功,就會成為完全不同的兩類。對于一個名為outer的外部類和其內部定義的名為inner的內部類。編譯完成后出現outer.class和outer$inner.class兩類。

            B:局部內部類

            在方法中定義的內部類稱為局部內部類。與局部變量類似,局部內部類不能有訪問說明符,因為它不是外圍類的一部分,但是它可以訪問當前代碼塊內的常量,和此外圍類所有的成員。

          publicclass Outer {
          privateints = 100;
          privateintout_i = 1;

          publicvoid f(finalint k) {
          finalint s = 200;
          int i = 1;
          finalint j = 10;

          //定義在方法內部
          class Inner {
          ints = 300; // 可以定義與外部類同名的變量

          // static int m = 20; //不可以定義靜態變量
          Inner(int k) {
          inner_f(k);
          }

          intinner_i = 100;

          voidinner_f(int k) {
          //如果內部類沒有與外部類同名的變量,在內部類中可以直接訪問外部類的實例變量
          System.out.println(out_i);
          //可以訪問外部類的局部變量(即方法內的變量),但是變量必須是final的
          System.out.println(j);
          //System.out.println(i);
          //如果內部類中有與外部類同名的變量,直接用變量名訪問的是內部類的變量
          System.out.println(s);
          //用this.變量名訪問的也是內部類變量
          System.out.println(this.s);
          //用外部類名.this.內部類變量名訪問的是外部類變量
          System.out.println(Outer.this.s);
          }
          }
          new Inner(k);
          }

          publicstaticvoid main(String[] args) {
          // 訪問局部內部類必須先有外部類對象
          Outer out = new Outer();
          out.f(3);
          }
          }

            C:靜態內部類(嵌套類):(注意:前兩種內部類與變量類似,所以可以對照參考變量)

            如果你不需要內部類對象與其外圍類對象之間有聯系,那你可以將內部類聲明為static。這通常稱為嵌套類(nested class)。想要理解static應用于內部類時的含義,你就必須記住,普通的內部類對象隱含地保存了一個引用,指向創建它的外圍類對象。然而,當內部類是static的時,就不是這樣了。嵌套類意味著:

            1. 要創建嵌套類的對象,并不需要其外圍類的對象。
            2. 不能從嵌套類的對象中訪問非靜態的外圍類對象。

          publicclass Outer {
          privatestaticinti = 1;
          privateintj = 10;
          publicstaticvoidouter_f1() {
          }

          publicvoidouter_f2() {
          }

          // 靜態內部類可以用public,protected,private修飾
          // 靜態內部類中可以定義靜態或者非靜態的成員
          staticclass Inner {
          staticintinner_i = 100;
          intinner_j = 200;
          staticvoidinner_f1() {
          //靜態內部類只能訪問外部類的靜態成員(包括靜態變量和靜態方法)
          System.out.println("Outer.i" + i);
          outer_f1();
          }

          voidinner_f2() {
          // 靜態內部類不能訪問外部類的非靜態成員(包括非靜態變量和非靜態方法)
          // System.out.println("Outer.i"+j);
          // outer_f2();
          }
          }

          publicvoidouter_f3() {
          // 外部類訪問內部類的靜態成員:內部類.靜態成員
          System.out.println(Inner.inner_i);
          Inner.inner_f1();
          // 外部類訪問內部類的非靜態成員:實例化內部類即可
          Inner inner = new Inner();
          inner.inner_f2();
          }

          publicstaticvoid main(String[] args) {
          newOuter().outer_f3();
          }
          }

            生成一個靜態內部類不需要外部類成員:這是靜態內部類和成員內部類的區別。靜態內部類的對象可以直接生成:Outer.Inner in = new Outer.Inner(); 而不需要通過生成外部類對象來生成。這樣實際上使靜態內部類成為了一個頂級類(正常情況下,你不能在接口內部放置任何代碼,但嵌套類可以作為接口的一部分,因為它是static 的。只是將嵌套類置于接口的命名空間內,這并不違反接口的規則)

            D:匿名內部類(from thinking in java 3th)

            簡單地說:匿名內部類就是沒有名字的內部類。什么情況下需要使用匿名內部類?如果滿足下面的一些條件,使用匿名內部類是比較合適的:

            ·只用到類的一個實例。
            ·類在定義后馬上用到。
            ·類非常小(SUN推薦是在4行代碼以下)
            ·給類命名并不會導致你的代碼更容易被理解。
            在使用匿名內部類時,要記住以下幾個原則:
            ·匿名內部類不能有構造方法。
            ·匿名內部類不能定義任何靜態成員、方法和類。
            ·匿名內部類不能是public,protected,private,static。
            ·只能創建匿名內部類的一個實例。
          ·一個匿名內部類一定是在new的后面,用其隱含實現一個接口或實現一個類。
            ·因匿名內部類為局部內部類,所以局部內部類的所有限制都對其生效。

            下面的例子看起來有點奇怪:

          //在方法中返回一個匿名內部類
          public class Parcel6 {
          public Contents cont() {
          return new Contents() {
          private int i = 11;

          public int value() {
          return i;
          }
          }; // 在這里需要一個分號
          }

          public static void main(String[] args) {
          Parcel6 p = new Parcel6();
          Contents c = p.cont();
          }
          }

            cont()方法將下面兩個動作合并在一起:返回值的生成,與表示這個返回值的類的定義!進一步說,這個類是匿名的,它沒有名字。更糟的是,看起來是你正要創建一個Contents對象:

          return new Contents()

            但是,在到達語句結束的分號之前,你卻說:“等一等,我想在這里插入一個類的定義”:

          return new Contents() {
          private int i = 11;
          public int value() { return i; }
          };

            這種奇怪的語法指的是:“創建一個繼承自Contents的匿名類的對象。”通過new 表達式返回的引用被自動向上轉型為對Contents的引用。匿名內部類的語法是下面例子的簡略形式:

          class MyContents implements Contents {
          private int i = 11;
          public int value() { return i; }
          }
          return new MyContents();

            在這個匿名內部類中,使用了缺省的構造器來生成Contents。下面的代碼展示的是,如果你的基類需要一個有參數的構造器,應該怎么辦:

          public class Parcel7 {
          public Wrapping wrap(int x) {
          // Base constructor call:
          return new Wrapping(x) { // Pass constructor argument.
          public int value() {
          return super.value() * 47;
          }
          }; // Semicolon required
          }
          public static void main(String[] args) {
          Parcel7 p = new Parcel7();
          Wrapping w = p.wrap(10);
          }
          }

            只需簡單地傳遞合適的參數給基類的構造器即可,這里是將x 傳進new Wrapping(x)。在匿名內部類末尾的分號,并不是用來標記此內部類結束(C++中是那樣)。實際上,它標記的是表達式的結束,只不過這個表達式正巧包含了內部類罷了。因此,這與別的地方使用的分號是一致的。

            如果在匿名類中定義成員變量,你同樣能夠對其執行初始化操作:

          public class Parcel8 {
          // Argument must be final to use inside
          // anonymous inner class:
          public Destination dest(final String dest) {
          return new Destination() {
          private String label = dest;
          public String readLabel() { return label; }
          };
          }
          public static void main(String[] args) {
          Parcel8 p = new Parcel8();
          Destination d = p.dest("Tanzania");
          }
          }

            如果你有一個匿名內部類,它要使用一個在它的外部定義的對象,編譯器會要求其參數引用是final 型的,就像dest()中的參數。如果你忘記了,會得到一個編譯期錯誤信息。如果只是簡單地給一個成員變量賦值,那么此例中的方法就可以了。但是,如果你想做一些類似構造器的行為,該怎么辦呢?在匿名類中不可能有已命名的構造器(因為它根本沒名字!),但通過實例初始化,你就能夠達到為匿名內部類“制作”一個構造器的效果。像這樣做:

          abstract class Base {
          public Base(int i) {
          System.out.println("Base constructor, i = " + i);
          }
          public abstract void f();
          }

          public class AnonymousConstructor {
          public static Base getBase(int i) {
          return new Base(i) {
          {
          System.out.println("Inside instance initializer");
          }
          public void f() {
          System.out.println("In anonymous f()");
          }
          };
          }
          public static void main(String[] args) {
          Base base = getBase(47);
          base.f();
          }
          }

            在此例中,不要求變量i 一定是final 的。因為i 被傳遞給匿名類的基類的構造器,它并不會在匿名類內部被直接使用。下例是帶實例初始化的“parcel”形式。注意dest()的參數必須是final,因為它們是在匿名類內被使用的。

          public class Parcel9 {
          public Destinationdest(final String dest, final float price) {
          return new Destination() {
          private int cost;
          // Instance initialization for each object:
          {
          cost = Math.round(price);
          if(cost > 100)
          System.out.println("Over budget!");
          }

          private String label = dest;
          public String readLabel() { return label; }
          };
          }
          public static void main(String[] args) {
          Parcel9 p = new Parcel9();
          Destination d = p.dest("Tanzania", 101.395F);
          }
          }

            在實例初始化的部分,你可以看到有一段代碼,那原本是不能作為成員變量初始化的一部分而執行的(就是if 語句)。所以對于匿名類而言,實例初始化的實際效果就是構造器。當然它受到了限制:你不能重載實例初始化,所以你只能有一個構造器。

            從多層嵌套類中訪問外部

            一個內部類被嵌套多少層并不重要,它能透明地訪問所有它所嵌入的外圍類的所有成員,如下所示:

          class MNA {
          private void f() {}
          class A {
          private void g() {}
          public class B {
          void h() {
          g();
          f();
          }
          }
          }
          }
          public class MultiNestingAccess {
          public static void main(String[] args) {
          MNA mna = new MNA();
          MNA.A mnaa = mna.new A();
          MNA.A.B mnaab = mnaa.new B();
          mnaab.h();
          }
          }

            可以看到在MNA.A.B中,調用方法g()和f()不需要任何條件(即使它們被定義為private)。這個例子同時展示了如何從不同的類里面創建多層嵌套的內部類對象的基本語法。“.new”語法能產生正確的作用域,所以你不必在調用構造器時限定類名。

            內部類的重載問題

            如果你創建了一個內部類,然后繼承其外圍類并重新定義此內部類時,會發生什么呢?也就是說,內部類可以被重載嗎?這看起來似乎是個很有用的點子,但是“重載”內部類就好像它是外圍類的一個方法,其實并不起什么作用:

          class Egg {
          private Yolk y;

          protectedclass Yolk {
          public Yolk() {
          System.out.println("Egg.Yolk()");
          }
          }

          public Egg() {
          System.out.println("New Egg()");
          y = new Yolk();
          }
          }

          publicclass BigEgg extends Egg {
          publicclass Yolk {
          public Yolk() {
          System.out.println("BigEgg.Yolk()");
          }
          }

          publicstaticvoid main(String[] args) {
          new BigEgg();
          }
          }


            輸出結果為:

          New Egg()
          Egg.Yolk()

            缺省的構造器是編譯器自動生成的,這里是調用基類的缺省構造器。你可能認為既然創建了BigEgg 的對象,那么所使用的應該是被“重載”過的Yolk,但你可以從輸出中看到實際情況并不是這樣的。

            這個例子說明,當你繼承了某個外圍類的時候,內部類并沒有發生什么特別神奇的變化。這兩個內部類是完全獨立的兩個實體,各自在自己的命名空間內。當然,明確地繼承某個內部類也是可以的:

          class Egg2 {
          protected class Yolk {
          public Yolk() {
          System.out.println("Egg2.Yolk()");
          }

          public void f() {
          System.out.println("Egg2.Yolk.f()");
          }
          }

          private Yolk y = new Yolk();

          public Egg2() {
          System.out.println("New Egg2()");
          }

          public void insertYolk(Yolk yy) {
          y = yy;
          }

          public void g() {
          y.f();
          }
          }

          public class BigEgg2 extends Egg2 {
          public class Yolk extends Egg2.Yolk {
          public Yolk() {
          System.out.println("BigEgg2.Yolk()");
          }

          public void f() {
          System.out.println("BigEgg2.Yolk.f()");
          }
          }

          public BigEgg2() {
          insertYolk(new Yolk());
          }

          public static void main(String[] args) {
          Egg2 e2 = new BigEgg2();
          e2.g();
          }
          }

            輸出結果為:

          Egg2.Yolk()
          New Egg2()
          Egg2.Yolk()
          BigEgg2.Yolk()
          BigEgg2.Yolk.f()

            現在BigEgg2.Yolk 通過extends Egg2.Yolk 明確地繼承了此內部類,并且重載了其中的方法。Egg2 的insertYolk()方法使得BigEgg2 將它自己的Yolk 對象向上轉型,然后傳遞給引用y。所以當g()調用y.f()時,重載后的新版的f()被執行。第二次調用Egg2.Yolk()是BigEgg2.Yolk 的構造器調用了其基類的構造器。可以看到在調用g()的時候,新版的f()被調用了。

            內部類的繼承問題(thinking in java 3th p294)

            因為內部類的構造器要用到其外圍類對象的引用,所以在你繼承一個內部類的時候,事情變得有點復雜。問題在于,那個“秘密的”外圍類對象的引用必須被初始化,而在被繼承的類中并不存在要聯接的缺省對象。要解決這個問題,需使用專門的語法來明確說清它們之間的關聯:

          class WithInner {
          class Inner {
          Inner(){
          System.out.println("this is a constructor in WithInner.Inner");
          };
          }
          }

          public class InheritInner extends WithInner.Inner {
          // ! InheritInner() {} // Won't compile
          InheritInner(WithInner wi) {
          wi.super();
          System.out.println("this is a constructor in InheritInner");
          }

          public static void main(String[] args) {
          WithInner wi = new WithInner();
          InheritInner ii = new InheritInner(wi);
          }
          }

            輸出結果為:

          this is a constructor in WithInner.Inner
          this is a constructor in InheritInner

            可以看到,InheritInner 只繼承自內部類,而不是外圍類。但是當要生成一個構造器時,缺省的構造器并不算好,而且你不能只是傳遞一個指向外圍類對象的引用。此外,你必須在構造器內使用如下語法:

          enclosingClassReference.super();

            這樣才提供了必要的引用,然后程序才能編譯通過。



          http://blog.sina.com.cn/s/blog_56898c310100a3i3.html
          posted @ 2012-04-14 02:11 abin 閱讀(525) | 評論 (0)編輯 收藏

          package com.abin.lee.reflect;

          import java.lang.reflect.Method;

          public class InvokeTester {
           public int add(int param1,int param2){
            return param1+param2;
           }
           public String echo(String message){
            return "hello"+message;
           }
           public static void main(String[] args) {
            try {
             Class<?> classType=InvokeTester.class;
             Object invokeTester=classType.newInstance();
             System.out.println(invokeTester instanceof InvokeTester);
             Method addMethod=classType.getMethod("add", new Class[]{int.class,int.class});
             Object result=addMethod.invoke(invokeTester, new Object[]{1,2});
             System.out.println((Integer)result);
             
             System.out.println("----------");
             Method echoMethod=classType.getMethod("echo", new Class[]{String.class});
             Object result2=echoMethod.invoke(invokeTester, new Object[]{"abin"});
             System.out.println(result2);
            } catch (Exception e) {
             e.printStackTrace();
             System.out.println(e.getMessage());
            }
           }
          }

          posted @ 2012-04-14 02:08 abin 閱讀(569) | 評論 (0)編輯 收藏

          package com.abin.lee.reflect;

          import java.lang.reflect.Method;

          public class DumpMethods {
           public static void main(String[] args) {
            try {
             Class clazz=Class.forName("java.util.Stack");
             Method method[]=clazz.getDeclaredMethods();
             for(int i=0;i<method.length;i++)
              System.out.println(method[i].toString());
            } catch (Exception e) {
             e.printStackTrace();
             System.err.println(e.getMessage());
            }
           }

          }

          posted @ 2012-04-14 01:02 abin 閱讀(753) | 評論 (0)編輯 收藏

          package com.abin.lee.test;

          import java.io.BufferedReader;
          import java.io.File;
          import java.io.FileInputStream;
          import java.io.InputStreamReader;

          public class FileTotal {
           
           public static void ReadSubdirectory(File dir){
            if(dir.isDirectory()){
             File[] subFile=dir.listFiles();
             for(int i=0;i<subFile.length;i++){
              if(subFile[i].isDirectory()){
               ReadSubdirectory(subFile[i]);
              }else{
               ReadSubFile(subFile[i]);
              }
             }
            }
           }
           public static void ReadSubFile(File file){
            int numCount=0;
            int letterCount=0;
            int spaceCount=0;
            int lineCount=0;
            int temp=0;
            try {
             FileInputStream input=new FileInputStream(file);
             while((temp=input.read())!=-1){
              if(temp>=48&&temp<=57){
               numCount++;
              }else if((temp>=65&&temp<=90)||(temp>97&&temp<122)){
               letterCount++;
              }else if(temp==32){
               spaceCount++;
              }
             }
             BufferedReader buffer=new BufferedReader(new InputStreamReader(new FileInputStream(file)));
             while(buffer.readLine()!=null){
              lineCount++;
             }
             System.out.println("文件路徑:"+file.getAbsolutePath());
             System.out.println("數字個數:"+numCount);
             System.out.println("字母個數:"+letterCount);
             System.out.println("空格個數:"+spaceCount);
             System.out.println("行數數:"+lineCount);
             
            } catch (Exception e) {
             e.printStackTrace();
            }
           }
           public static void main(String[] args) {
            ReadSubdirectory(new File("D://image"));
           }
          }

          posted @ 2012-03-31 22:02 abin 閱讀(1306) | 評論 (0)編輯 收藏

          今天在項目中用了mybatis的resultMap。以前用的時候都是一些簡單的查詢,修改,分頁。這次涉及到了POJO對象之間的一對多和多對一的關系映射。

              mybatis有幾種使用方式, 我喜歡用mapper的方式,然后用spring來管理mybatis.

              開發工具是Eclipse jee, mybatis版本是3.0.5, mybatis-sprint-1.0.1

             工程文件目錄

          mybatis-config.xml 是mybatis的配置文件:

           

          <configuration>
              <settings>
                  <setting name="cacheEnabled" value="false" />
                  <setting name="useGeneratedKeys" value="true" />
                  <setting name="defaultExecutorType" value="REUSE" />
              </settings>
          	<mappers>
                  <mapper resource="com/exam/persistence/mapper/ClientMapper.xml" />
              </mappers>
          </configuration>

          applicationContext.xml:

           

          <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
          	<property name="dataSource" ref="dataSource" />
          	<property name="configLocation" value="/WEB-INF/mybatis-config.xml" />
          </bean>

          <bean id="clientMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

              <property name="mapperInterface" value="com.exam.persistence.mapper.ClientMapper" />

              <property name="sqlSessionFactory" ref="sqlSessionFactory" />

          </bean>

          配置文件就是這些了。主要的東西在下面:

          業務邏輯涉及到三張表: Client, Subscriber, Account. 其中Client表和Subscriber表是多對一的關系. Client表和Account是一對多的關系。

           在com.example.persistence.mapper目錄下,需要創建兩個文件分別是:ClientMapper.java 和 ClientMapper.xml

          對象映射關系主要在ClientMapper.xml中定義:

           

          <?xml version="1.0" encoding="UTF-8" ?>
          <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
          <mapper namespace="com.exam.persistence.mapper.ClientMapper">
              <resultMap id="clients" type="com.exam.entity.Clients">
              	<id property="externalId" column="externalId" />
              	<result property="id" column="id"/>
              	<result property="subscriptionId" column="subscriptionId"/>
              	<association property="subscription" column="subscriptionId" javaType="com.exam.entity.Subscription" select="selectSubscription"/>
              	<collection property="accounts" column="id" ofType="com.exam.entity.Accounts" select="selectAccounts"/>
              </resultMap>
              
              <select id="getClientByID" resultMap="clients" parameterType="java.lang.String">
                 select 
                     client.internal_id as id,
                     client.external_id as externalId,
                 from CLIENT client 
                      left outer join SUBSCRIPTION subscription on client.subscription_id = subscription.subscription_id
                      left outer join ACCOUNT accounts on client.internal_id = accounts.id
                  where client.external_id = #{external_id}
              </select>
              
              <select id="selectAccounts" parameterType="int" resultType="com.exam.entity.Accounts">
              	select * from ACCOUNT where client_id=#{client_id}
              </select>
              <select id="selectSubscription" parameterType="java.lang.String" resultType="com.exam.entity.Subscription">
              	select * from SUBSCRIPTION where subscription_id = #{subscription_id}
              </select>
          </mapper>

          這個xml文件定義了一個resultMap id="clients". clients里面包含了一個assoction(多對一)和一個collection(一對多). 這兩個分別對應了兩個select id.

           ClientMapper.java是一個interface:

          import java.util.List;
          import com.exam.entity.Clients;
          public interface ClientMapper {
            public List<Clients> getClientByID(String external_id);
          }

          其中函數名"getClientByID"應該和ClientMapper.xml中的select id的值相同。

           在com.exam.entity目錄下面需要定義Clients, Accounts, Subscription 三個POJO類。就不在這里寫POJO類了。

          這樣我們在service邏輯中就可以使用ClientMapper.

           

          public class ClientServiceImpl implements ClientService {
          	private ClientMapper clientMapper;
          
          	public ClientMapper getClientMapper() {
          		return deviceMapper;
          	}
          
          	public void setClientMapper(ClientMapper clientMapper) {
          		this.clientMapper = clientMapper;
          	}
          
                   @Override
          	public List<Clients> getClientByID(String external_id) {
          	    return getClientMapper().getClientByID(external_id);
          	}
          }我們需要在applicationContext中把clientMapper注入到這個server類中就ok了。
          先寫到這里。




          http://m.oschina.net/blog/29845
          posted @ 2012-03-28 22:23 abin 閱讀(4849) | 評論 (0)編輯 收藏

          在applicationContext.xml中有如下配置:

          <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
              <property name="sessionFactory">
                 <ref bean="sessionFactory"/>
              </property>
          </bean>


          也可以:
          <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
              <property name="sessionFactory">
                 <ref bean="sessionFactory"/>
              </property>
          </bean>

          兩種實現方式其實沒有區別,尤其是第二種不要自己去關閉session,session在事務結束后都會自動關閉。 但是一定要注意延遲加載的問題,當對象在session關閉前沒有從數據庫中取得,而jsp中需要展示對象時,會提示LazyInitializationException,你可以通過OpenSessionInViewFilter來保證延遲加載不會出現錯誤,即:
          <filter>
               <filter-name>opensession</filter-name>
               <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
          </filter>
          <filter-mapping>
               <filter-name>opensession</filter-name>
               <url-pattern>*.do</url-pattern>
          </filter-mapping>


          posted @ 2012-03-27 22:30 abin 閱讀(1005) | 評論 (0)編輯 收藏

          package com.abin.inter.test;

          public class SplitString1 {
           public static void main(String[] args) {
            StringBuffer stb = new StringBuffer();
            String unitId1 = "aaaaa";
            String callerNumber1 = "bbbbb";
            String calleeNumber1 = "ccccc";
            stb.append(unitId1).append("|").append(callerNumber1).append("|")
              .append(calleeNumber1);
            System.out.println("stb=" + stb.toString());
            String unitId = stb.toString()
              .substring(0, stb.toString().indexOf("|"));
            System.out.println("unitId=" + unitId);
            String temp1 = stb.toString().substring(unitId.length() + 1,
              stb.toString().length() - unitId.length());
            System.out.println("temp1=" + temp1);
            String callerNumber = temp1.substring(0, temp1.indexOf("|"));
            System.out.println("callerNumber=" + callerNumber);
            System.out.println("unitId.length()=" + unitId.length());
            System.out.println("callerNumber.length()=" + callerNumber.length());
            System.out.println("stb=" + stb.toString().length());
            String temp2 = stb.toString().substring(
              unitId.length() + callerNumber.length() + 2,
              stb.toString().length());
            System.out.println("temp2=" + temp2);
            String calleeNumber = temp2.substring(0, temp2.length());
            System.out.println("calleeNumber=" + calleeNumber);
           }
          }

          posted @ 2012-03-27 20:04 abin 閱讀(506) | 評論 (0)編輯 收藏

          小弟最近開發OA系統里面的一個郵件模塊, 基本的收發功能是實現了,但是不是很完善。

           

          特別是在控制郵件中的附件時,點擊收件箱,附件和內容 都開始接收,問題是出在這里?

          1.如果接受1000封或者更多,附件為1M或者更大,那么服務器要控制以G為單位的附件下載,速度肯定會很慢的,

          2.問老大,老大沒有直接回答,叫我們想想,他給意見是附件在凌晨自動開始下載。(這個只是老大為了,給我們思路)。

          3.老大說最好的效果是:點擊收件箱,頁面開始接收每封郵件的標題(內容,和附件不管),點擊某封郵件的標題,開始接收郵件的內容(同時標題也接受,內容中的附件不接收),但點擊附件時開始接受。

          4.感覺這個想法比較好,按照老大說的這種頁面怎么分開請求,

          5.不知道各位前輩有沒有更好的設計思路。

           

          謝謝各位看完啊!

           小弟第一次發,前輩多多支持哦!

           

           

           

           

           

          這種方式用ajax來實現就最完美解決 
          點擊收件箱,頁面開始接收每封郵件的標題(內容,和附件不管),點擊某封郵件的標題,開始接收郵件的內容(同時標題也接受,內容中的附件不接收),但點擊附件時開始接受。 

          每個都是一個單獨的請求,每次都得到想要的那部分數據,用ajax來做 

          posted @ 2012-03-27 19:43 abin 閱讀(673) | 評論 (1)編輯 收藏

          #include "stdio.h"
          int main(int argc,char *argv[])
          {
           FILE *fp;
           char ch;
           if((fp=fopen("bing.doc","wt+"))==NULL){
            printf("CANNOT open this bing.txt");
            getch();
            exit(0);
           }
           printf("input a string :\n");
           ch=getchar();
           while(ch!='\n')
           {
            fputc(ch,fp);
            ch=getchar(); 
           }
           rewind(fp);
           ch=fgetc(fp);
           while(ch!=EOF)
           {
            putchar(ch);
            ch=fgetc(fp);
           }
           printf("\n");
           fclose(fp);
           
          }
          posted @ 2012-03-26 21:13 abin 閱讀(260) | 評論 (0)編輯 收藏

          Java容器集合類的區別用法

          Set,List,Map,Vector,ArrayList的區別

          JAVA的容器---List,Map,Set
          Collection
          ├List
          │├LinkedList
          │├ArrayList
          │└Vector
          │ └Stack
          └Set
          Map
          ├Hashtable
          ├HashMap
          └WeakHashMap

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

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

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

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

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

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

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

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

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

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

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

          總結
            如果涉及到堆棧,隊列等操作,應該考慮用List,對于需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
            如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。
            要特別注意對哈希表的操作,作為key的對象要正確復寫equals和hashCode方法。
            盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。

          Java 集合類 map set list arraylist hashmap hashtable(轉)

          Vector的方法都是同步的(Synchronized),是線程安全的(thread-safe),而ArrayList的方法不是,由于線程的同步必然要影響性能,因此,ArrayList的性能比Vector好。
          當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利于節約內存空間。
          Hashtable和HashMap  
          它們的性能方面的比較類似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。
          ArrayList和LinkedList  
          對 于處理一列數據項,Java提供了兩個類ArrayList和LinkedList,ArrayList的內部實現是基于內部數組Object[],所以 從概念上講,它更象數組,但LinkedList的內部實現是基于一組連接的記錄,所以,它更象一個鏈表結構,所以,它們在性能上有很大的差別。  
          (1) 從上面的分析可知,在ArrayList的前面或中間插入數據時,你必須將其后的所有數據相應的后移,這樣必然要花費較多時間,所以,當你的操作是在一列 數據的后面添加數據而不是在前面或中間,并且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能。  
          (2)而訪問鏈表中的某個元素時,就必須從鏈表的一端開始沿著連接方向一個一個元素地去查找,直到找到所需的元素為止,所以,當你的操作是在一列數據的前面或中間添加或刪除數據,并且按照順序訪問其中的元素時,就應該使用LinkedList了。  
          (3)如果在編程中,1,2兩種情形交替出現,這時,你可以考慮使用List這樣的通用接口,而不用關心具體的實現,在具體的情形下,它的性能由具體的實現來保證。
          設置集合類的初始大小
          在Java 集合框架中的大部分類的大小是可以隨著元素個數的增加而相應的增加的,我們似乎不用關心它的初始大小,但如果我們考慮類的性能問題時,就一定要考慮盡可能 地設置好集合對象的初始大小,這將大大提高代碼的性能,比如,Hashtable缺省的初始大小為101,載入因子為0.75,即如果其中的元素個數超過 75個,它就必須增加大小并重新組織元素,所以,如果你知道在創建一個新的Hashtable對象時就知道元素的確切數目如為110,那么,就應將其初始 大小設為110/0.75=148,這樣,就可以避免重新組織內存并增加大小。
          特別要理解的:
          Hashtable類
            Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。
            添加數據使用put(key, value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。
          Hashtable 通過initial capacity和load factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的 均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。
          使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:
              Hashtable numbers = new Hashtable();
              numbers.put(“one”, new Integer(1));
              numbers.put(“two”, new Integer(2));
              numbers.put(“three”, new Integer(3));
            要取出一個數,比如2,用相應的key:
              Integer n = (Integer)numbers.get(“two”);
              System.out.println(“two = ” + n);
             由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方 法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相 同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如 果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希 表的操作。
            如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。
            Hashtable是同步的。
          HashMap類
             HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但 是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比 例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。
          LinkedList類
             LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在 LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
            注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
              List list = Collections.synchronizedList(new LinkedList(...));
          ArrayList類
            ArrayList實現了可變大小的數組。它允許所有元素,包括null。ArrayList沒有同步。
          size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。
             每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法并 沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
            和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。
          Vector類
             Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和ArrayList創建的 Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例 如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該 異常。

          細說Java之util類:

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

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

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

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

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

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

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

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

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

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

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

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

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

          總結
            如果涉及到堆棧,隊列等操作,應該考慮用List,對于需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
            如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。
            要特別注意對哈希表的操作,作為key的對象要正確復寫equals和hashCode方法。
            盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

           

          posted @ 2012-03-23 12:31 abin 閱讀(897) | 評論 (0)編輯 收藏

          僅列出標題
          共50頁: First 上一頁 40 41 42 43 44 45 46 47 48 下一頁 Last 
          主站蜘蛛池模板: 班玛县| 花垣县| 蒙自县| 姚安县| 阜新| 绵竹市| 怀宁县| 双鸭山市| 武陟县| 玉溪市| 泰来县| 云浮市| 申扎县| 共和县| 洮南市| 二手房| 新晃| 汉阴县| 白玉县| 盐津县| 德江县| 孟州市| 清徐县| 临汾市| 礼泉县| 商水县| 金寨县| 乐至县| 新巴尔虎左旗| 马龙县| 女性| 隆回县| 肃宁县| 屯昌县| 临漳县| 通化市| 旺苍县| 贵阳市| 类乌齐县| 沙河市| 陈巴尔虎旗|