2008年12月6日

          IoC   :   Inversion of Control

          spring是通過依賴注入(Dependency Injection )實現的IoC

          IoC容器

             *   必須將被管理的對象定義到spring配置文件中
             *   必須定義constructor或者setter方法,讓spring將對象注入進去

          AOP  :  Aspect Oriented Programming

          spring帶來了一種編程方式,面向切面的編程。

          AOP是一個概念

          在一個程序中分離一個功能,這種功能的實現是與程序不相關的類。
          同時能夠使很多類共享這個功能。

          關注是他的主要點,要關注某個功能,要關注切入點。

          實現AOP有2點:
          1、Pointcut(切入點)是一個范圍---表達式
          2、Advice(具體實現)功能放到那個方法



          spring對hibernate的支持

          注入SessionFactory到spring配置文件中

          <Bean id="SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactory">
                  <property nema="configLocation">
                          <value>classpath:hibernate.cfg.xml</value>
                  </property>
          </Bean>

          posted @ 2009-02-13 08:40 天長 閱讀(127) | 評論 (0)編輯 收藏
           
          在庫中建表時語句為: create table tbname(..........)engine=MyISAM character set gbk collate gbk_chinese_ci;


          程序中連接數據庫的Connection對象需要寫成Connection con = DriverManaager.getConnection("jdbc:mysql://...user=..&password=...&useUnicode=true&characterEncoding=gbk");
          若在終端下用mysql命令向數據庫插入數據,則在進入mysql時的命令寫成:#mysql --default-character-set=gbk -u ... -p

          在網上看過很多解決mysql亂碼的帖子,可是寫的不是羅里羅嗦就過于復雜。其實亂碼沒那么復雜,是網上的大俠們想多了。我研究過一段日子,總結出一套自己的解決方案,如果你還沒解決亂碼就用我的方法試一下。我的方案不是最好的,卻是最簡單易懂的。不信你試試。

          在使用MYSQL時,插入中文字符,經常會出現亂碼,中文全被用?代替。出現這種情況的原因,多是字符集不匹配造成的。
          在MYSQL中,如果使用缺省的字符集,在建庫、建表時,默認使用的是latin1字符集,為ISO 8859-1西歐字符集。插入中文字符時,與之不匹配,就會出現亂碼。

          要解決此問題,就必須手動將數據庫Server和Client的字符編碼改為gb2312。配置方法如下:
          打開MYSQL安裝目錄下的my.ini文件,找到如下段落:

          # CLIENT SECTION
          # ----------------------------------------------------------------------
          #
          # The following options will be read by MySQL client applications.
          # Note that only client applications shipped by MySQL are guaranteed
          # to read this section. If you want your own MySQL client program to
          # honor these values, you need to specify it as an option during the
          # MySQL client library initialization.
          #
          [client]

          port=3306

          [mysql]

          default-character-set=latin1


          # SERVER SECTION
          # ----------------------------------------------------------------------
          #
          # The following options will be read by the MySQL Server. Make sure that
          # you have installed the server correctly (see above) so it reads this
          # file.
          #
          [mysqld]

          # The TCP/IP Port the MySQL Server will listen on
          port=3306

          #Path to installation directory. All paths are usually resolved relative to this.
          basedir="D:/MySQL/MySQL Server 5.0/"

          #Path to the database root
          datadir="D:/MySQL/MySQL Server 5.0/Data/"

          # The default character set that will be used when a new schema or table is
          # created and no character set is defined
          default-character-set=latin1

          將其中的default-character-set=latin1改為default-character-set=gb2312( 兩個都改),然后重啟MYSQL(特別注意:以前建立的數據庫要重建,因為以前存儲的數據編碼方式為ISO-8859-1),運行MySQL Command Line Client:
          輸入show variables like 'character_set_%';可以查看數據庫的字符編碼如下:

          mysql> show variables like 'character_set_%';
          +--------------------------+-----------------------------------------+
          | Variable_name             | Value                                     |
          +--------------------------+-----------------------------------------+
          | character_set_client      | gb2312                                   |
          | character_set_connection | gb2312                                |
          | character_set_database    | gb2312                                |
          | character_set_filesystem | binary                                   |
          | character_set_results     | gb2312                                   |
          | character_set_server      | gb2312                                  |
          | character_set_system      | utf8                                     |
          | character_sets_dir        | D:\MySQL\MySQL Server 5.0\share\charsets|
          +--------------------------+-----------------------------------------+

          然后,在程序中將連接數據庫的URL改為jdbc:mysql://localhost:3306/databasename?useUnicode=true&amp;characterEncoding=gb2312   就可以了!(&amp;是代表xml中的&)

          還需要注意到是:1.你的JSP頁面一定別忘了加上編碼方式<%@ page pageEncoding="GB2312"%>。

          2.把以前寫過濾方法如:getbytes(iso-8859-1)全去掉

          最后記住,一定要重新導入或建立數據庫!!!

          posted @ 2009-01-20 07:19 天長 閱讀(142) | 評論 (0)編輯 收藏
           
          馬老師說過,方法的重寫一定要去父類拷貝。
          今天深深的明白了這個道理。
          今天寫了個struts練習小項目。
          寫個控制器的類要繼承Action類復寫execute()
          public ActionForward execute(
                 ActionMapping mapping,
                 ActionForm form,
                 HttpServletRequest request
                 HttpServletResponse response) throws Exception {
            
          return null;
          }
          由于我是手寫的,結果形參的順序沒寫對。
          惡心了我一下午。
          還有異常的方法也要一樣。
          posted @ 2009-01-01 20:10 天長 閱讀(126) | 評論 (0)編輯 收藏
           

          單態定義:
          Singleton模式主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。

          Singleton模式就為我們提供了這樣實現的可能。使用Singleton的好處還在于可以節省內存,因為它限制了
          實例的個數,有利于Java垃圾回收(garbage collection)。

          使用Singleton注意事項:
          有時在某些情況下,使用Singleton并不能達到Singleton的目的,如有多個Singleton對象同時被不同的類
          裝入器裝載;在EJB這樣的分布式系統中使用也要注意這種情況,因為EJB是跨服務器,跨JVM的

          單態模式的演化:
          單態模式是個簡單的模式,但是這個簡單的模式也有很多復雜的東西。

          一,首先最簡單的單態模式,單態模式1
          import java.util.*;
          class Singleton
          {
            private static Singleton instance;
            private Vector v;
            private boolean inUse;

            private Singleton()
            {
              v = new Vector();
              v.addElement(new Object());
              inUse = true;
            }

            public static Singleton getInstance()
            {
              if (instance == null)          //1
                instance = new Singleton();  //2
              return instance;               //3
            }
          }
          這個單態模式是不安全的,為什么說呢 ?因為沒考慮多線程,如下情況
          Thread 1 調用getInstance() 方法,并且判斷instance是null,然後進入if模塊,
          在實例化instance之前,
          Thread 2搶占了Thread 1的cpu
          Thread 2 調用getInstance() 方法,并且判斷instance是null,然後進入if模塊,
          Thread 2 實例化instance 完成,返回
          Thread 1 再次實例化instance
          這個單態已經不在是單態

          二,為了解決剛才的問題:單態模式2
          public static synchronized Singleton getInstance()
          {
            if (instance == null)          //1
              instance = new Singleton();  //2
            return instance;               //3
          }
          采用同步來解決,這種方式解決了問題,但是仔細分析
          正常的情況下只有第一次時候,進入對象的實例化,須要同步,
          其它時候都是直接返回已經實例化好的instance不須要同步,
          大家都知到在一個多線程的程序中,如果同步的消耗是很大的,很容易造成瓶頸

          三,為了解決上邊的問題:單態模式3,加入同步
          public static Singleton getInstance()
          {
            if (instance == null)
            {
              synchronized(Singleton.class) {
                instance = new Singleton();
              }
            }
            return instance;
          }
          同步改成塊同步,而不使用函數同步,但是仔細分析,
          又回到了模式一的狀態,再多線程的時候根本沒有解決問題

          四,為了對應上邊的問題:單態模式4,也就是很多人采用的Double-checked locking
          public static Singleton getInstance()
          {
            if (instance == null)
            {
              synchronized(Singleton.class) {  //1
                if (instance == null)          //2
                  instance = new Singleton();  //3
              }
            }
            return instance;
          }
          這樣,模式一中提到的問題解決了。不會出現多次實例化的現象
          當第一次進入的時候,保正實例化時候的單態,在實例化后,多線程訪問的時候直接返回,不須要進入同步模塊,
          既實現了單態,又沒有損失性能。表面上看我們的問題解決了,但是再仔細分析:
          我們來假象這中情況:
          Thread 1 :進入到//3位置,執行new Singleton(),但是在構造函數剛剛開始的時候被Thread2搶占cpu
          Thread 2 :進入getInstance(),判斷instance不等于null,返回instance,
          (instance已經被new,已經分配了內存空間,但是沒有初始化數據)
          Thread 2 :利用返回的instance做某些操做,失敗或者異常
          Thread 1 :取得cpu初始化完成
          過程中可能有多個線程取到了沒有完成的實例,并用這個實例作出某些操做。
          -----------------------------------------
          出現以上的問題是因為
          mem = allocate();             //分配內存
          instance = mem;               //標記instance非空
                                        //未執行構造函數,thread 2從這里進入
          ctorSingleton(instance);      //執行構造函數
                                        //返回instance
          ------------------------------------------                             

          五,證明上邊的假想是可能發生的,字節碼是用來分析問題的最好的工具,可以利用它來分析
          下邊一段程序:(為了分析方便,所以漸少了內容)
          字節碼的使用方法見這里,利用字節碼分析問題
          class Singleton
          {
            private static Singleton instance;
            private boolean inUse;
            private int val; 

            private Singleton()
            {
              inUse = true;
              val = 5;
            }
            public static Singleton getInstance()
            {
              if (instance == null)
                instance = new Singleton();
              return instance;
            }
          }
          得到的字節碼                           
          ;asm code generated for getInstance
          054D20B0   mov         eax,[049388C8]      ;load instance ref
          054D20B5   test        eax,eax             ;test for null
          054D20B7   jne         054D20D7
          054D20B9   mov         eax,14C0988h
          054D20BE   call        503EF8F0            ;allocate memory
          054D20C3   mov         [049388C8],eax      ;store pointer in
                                                     ;instance ref. instance 
                                                     ;non-null and ctor
                                                     ;has not run
          054D20C8   mov         ecx,dword ptr [eax]
          054D20CA   mov         dword ptr [ecx],1   ;inline ctor - inUse=true;
          054D20D0   mov         dword ptr [ecx+4],5 ;inline ctor - val=5;
          054D20D7   mov         ebx,dword ptr ds:[49388C8h]
          054D20DD   jmp         054D20B0

          上邊的字節碼證明,猜想是有可能實現的

          六:好了,上邊證明Double-checked locking可能出現取出錯誤數據的情況,那么我們還是可以解決的
          public static Singleton getInstance()
          {
            if (instance == null)
            {
              synchronized(Singleton.class) {      //1
                Singleton inst = instance;         //2
                if (inst == null)
                {
                  synchronized(Singleton.class) {  //3
                    inst = new Singleton();        //4
                  }
                  instance = inst;                 //5
                }
              }
            }
            return instance;
          }
          利用Double-checked locking 兩次同步,中間變量,解決上邊的問題。
          (下邊這段話我只能簡單的理解,翻譯過來不好,所以保留原文,list 7是上邊的代碼,list 8是下邊的
          The code in Listing 7 doesn't work because of the current definition of the memory model.
           The Java Language Specification (JLS) demands that code within a synchronized block
           not be moved out of a synchronized block. However, it does not say that
           code not in a synchronized block cannot be moved into a synchronized block.
          A JIT compiler would see an optimization opportunity here.
          This optimization would remove the code at
          //4 and the code at //5, combine it and generate the code shown in Listing 8:)
          ------------------------------------------------- 
          list 8
          public static Singleton getInstance()
          {
            if (instance == null)
            {
              synchronized(Singleton.class) {      //1
                Singleton inst = instance;         //2
                if (inst == null)
                {
                  synchronized(Singleton.class) {  //3
                    //inst = new Singleton();      //4
                    instance = new Singleton();              
                  }
                  //instance = inst;               //5
                }
              }
            }
            return instance;
          }
          If this optimization takes place, you have the same out-of-order write problem we discussed earlier.
          如果這個優化發生,將再次發生上邊提到的問題,取得沒有實例化完成的數據。
          -------------------------------------------------

          以下部分為了避免我翻譯錯誤誤導打家,保留原文

          Another idea is to use the keyword volatile for the variables inst and instance.
          According to the JLS (see Resources), variables declared volatile are supposed to
          be sequentially consistent, and therefore, not reordered.
          But two problems occur with trying to use volatile to fix the problem with
          double-checked locking:

          The problem here is not with sequential consistency.
          Code is being moved, not reordered.

          Many JVMs do not implement volatile correctly regarding sequential consistency anyway.
          The second point is worth expanding upon. Consider the code in Listing 9:

          Listing 9. Sequential consistency with volatile

          class test
          {
            private volatile boolean stop = false;
            private volatile int num = 0;

            public void foo()
            {
              num = 100;    //This can happen second
              stop = true;  //This can happen first
              //...
            }

            public void bar()
            {
              if (stop)
                num += num;  //num can == 0!
            }
            //...
          }
           
          According to the JLS, because stop and num are declared volatile,
          they should be sequentially consistent. This means that if stop is ever true,
          num must have been set to 100.
          However, because many JVMs do not implement the sequential consistency feature of volatile,
          you cannot count on this behavior.
          Therefore, if thread 1 called foo and thread 2 called bar concurrently,
          thread 1 might set stop to true before num is set to 100.
          This could lead thread 2 to see stop as true, but num still set to 0.
          There are additional problems with volatile and the atomicity of 64-bit variables,
          but this is beyond the scope of this article.
          See Resources for more information on this topic.

          簡單的理解上邊這段話,使用volatile有可能能解決問題,volatile被定義用來保正一致性,但是很多虛擬機
          并沒有很好的實現volatile,所以使用它也會存在問題。

          最終的解決方案:
           (1),單態模式2,使用同步方法
           (2),放棄同步,使用一個靜態變量,如下
          class Singleton
          {
            private Vector v;
            private boolean inUse;
            private static Singleton instance = new Singleton();

            private Singleton()
            {
              v = new Vector();
              inUse = true;
              //...
            }

            public static Singleton getInstance()
            {
              return instance;
            }
          }
          但使用靜態變量也會存在問題,問題見 這篇文章

          而且如在文章開頭提到的,使用EJB跨服務器,跨JVM的情況下,單態更是問題

          好了是不是感覺單態模式根本沒法使用了,其實上邊都是特殊情況,這中特殊情況的出現是有條件的,只要
          根據你的具體應用,回避一些,就能解決問題,所以單態還是可以使用的。但是在使用前慎重,自己考慮好自己
          的情況適合哪種情況。 

          posted @ 2008-12-31 15:13 天長 閱讀(579) | 評論 (0)編輯 收藏
           
          2種實現線程的方法:1.繼承Thread類。 2.實現Runnable接口。
          多個線程操作同一資源的問題(不同步):第一個線程正操作資源,還沒完成,第二個線程也來操作。
          出現了資源錯位。
          解決的方法是資源的同步(synchronized)。即:一個線程訪問資源的時候,別的線程不能訪問該資源。
          實現同步有2種方法: 1.把方法同步。  2.同步代碼塊。
          實現了同步特征:1.線程安全了。 2.性能差了。(異步正好相反)
          Object中的wait(),使線程進入等待狀態,需要別的線程notify()繼續工作。
          wait()必須要在同步的情況下才能使用。
          隨之帶來了死鎖的問題。
          面試題:
          一、wait()和sleep()區別?
          wait方法是Object類中的方法。
          sleep方法是Thread類中的方法。

          當線程進入wait時別的線程可以訪問鎖定的對象。
          當線程進入sleep時別的線程不能訪問鎖定的對象。

          二、寫一個死鎖。
          class Demo implements Runnable {
              
          int flag ;
              
          static Object o1 = new Object(), o2 = new Object();
              
          public void run(){
                  System.out.println(
          "線程" + flag + "在運行。。");
                  
          if(flag == 1){
                      
          synchronized(o1){
                          
          try {
                              Thread.sleep(
          100);
                          } 
          catch(InterruptedException e) {
                              e.printStackTrace();
                          }
                          System.out.println(
          "線程1 --> o1");
                          
          synchronized(o2){
                              System.out.println(
          "線程1 --> o2");
                          }
                      }
                  }
                  
          if(flag == 2){
                      
          synchronized(o2){
                          
          try {
                              Thread.sleep(
          100);
                          } 
          catch(InterruptedException e) {
                              e.printStackTrace();
                          }
                          System.out.println(
          "線程2 --> o2");
                          
          synchronized(o1){
                              System.out.println(
          "線程2 --> o1");
                          }
                      }
                  }
              }
          }

          結果導致死鎖。

          線程1在運行。。
          線程2在運行。。
          線程1 
          --> o1
          線程2 
          --> o2
          不能繼續進行。

          2個Object類為static,說明他們鎖定的是同2個對象;

          三、Producer和Consumer的問題
          涉及了wait方法和nofity方法
          public class ProducerConsumer {
              
          public static void main(String[] args) {
                  SyncStack ss 
          = new SyncStack();
                  Producer p 
          = new Producer(ss);
                  Consumer c 
          = new Consumer(ss);
                  
          new Thread(p).start();
                  
          new Thread(c).start();
              }
          }

          class WoTou {
              
          int id; 
              WoTou(
          int id) {
                  
          this.id = id;
              }
              
          public String toString() {
                  
          return "WoTou : " + id;
              }
          }

          class SyncStack {
              
          int index = 0;
              WoTou[] arrWT 
          = new WoTou[6];
              
              
          public synchronized void push(WoTou wt) {
                  
          while(index == arrWT.length) {
                      
          try {
                          
          this.wait();
                      } 
          catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
                  
          this.notifyAll();        
                  arrWT[index] 
          = wt;
                  index 
          ++;
              }
              
              
          public synchronized WoTou pop() {
                  
          while(index == 0) {
                      
          try {
                          
          this.wait();
                      } 
          catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
                  
          this.notifyAll();
                  index
          --;
                  
          return arrWT[index];
              }
          }

          class Producer implements Runnable {
              SyncStack ss 
          = null;
              Producer(SyncStack ss) {
                  
          this.ss = ss;
              }
              
              
          public void run() {
                  
          for(int i=0; i<20; i++) {
                      WoTou wt 
          = new WoTou(i);
                      ss.push(wt);
          System.out.println(
          "生產了:" + wt);
                      
          try {
                          Thread.sleep((
          int)(Math.random() * 200));
                      } 
          catch (InterruptedException e) {
                          e.printStackTrace();
                      }            
                  }
              }
          }

          class Consumer implements Runnable {
              SyncStack ss 
          = null;
              Consumer(SyncStack ss) {
                  
          this.ss = ss;
              }
              
              
          public void run() {
                  
          for(int i=0; i<20; i++) {
                      WoTou wt 
          = ss.pop();
          System.out.println(
          "消費了: " + wt);
                      
          try {
                          Thread.sleep((
          int)(Math.random() * 1000));
                      } 
          catch (InterruptedException e) {
                          e.printStackTrace();
                      }            
                  }
              }
          }

          posted @ 2008-12-30 13:51 天長 閱讀(134) | 評論 (0)編輯 收藏
           
          初學 Java 有段時間了,感覺似乎開始入了門,有了點兒感覺
          但是發現很多困惑和疑問而且均來自于最基礎的知識
          折騰了一陣子又查了查書,終于對 String 這個特殊的對象有了點感悟

          大家先來看看一段奇怪的程序:
          public class TestString {
          public static void main(String[] args) {
          String s1 = "Monday";
          String s2 = "Monday";
          }
          }
           
          這個程序真是簡單啊!可是有什么問題呢?

          1. 來自 String 的憂慮
          上面這段程序中,到底有幾個對象呢?
          可能很多人脫口而出:兩個,s1 和 s2
          為什么?
          String 是 final 類,它的值不可變。
          看起來似乎很有道理,那么來檢測一下吧,稍微改動一下程序
          就可以看到結果了:

          public class TestString {
          public static void main(String[] args) {
          String s1 = "Monday";
          String s2 = "Monday";
          if (s1 == s2)
          System.out.println("s1 == s2");
          else
          System.out.println("s1 != s2");
          }
          }
          呵呵,很多人都會說已經不止兩個對象了
          編譯并運行程序,輸出:s1 == s2
          啊!
          為什么 s1 == s2 ?
          == 分明是在說:s1 與 s2 引用同一個 String 對象 -- "Monday"!

          2. 千變萬化的 String 再稍微改動一下程序,會有更奇怪的發現:
          public class TestString {
          public static void main(String[] args) {
          String s1 = "Monday";
          String s2 = new String("Monday");
          if (s1 == s2)
          System.out.println("s1 == s2");
          else
          System.out.println("s1 != s2");
          if (s1.equals(s2))
          System.out.println("s1 equals s2");
          else
          System.out.println("s1 not equals s2");
          }
          }
          我們將 s2 用 new 操作符創建
          程序輸出:
          s1 != s2
          s1 equals s2
          嗯,很明顯嘛
          s1 s2分別引用了兩個"Monday"String對象
          可是為什么兩段程序不一樣呢?

          3. 在 String 的游泳池中游泳
          哈哈,翻了翻書終于找到了答案:
          原來,程序在運行的時候會創建一個字符串緩沖池
          當使用 s2 = "Monday" 這樣的表達是創建字符串的時候,程序首先會
          在這個String緩沖池中尋找相同值的對象,在第一個程序中,s1先被
          放到了池中,所以在s2被創建的時候,程序找到了具有相同值的 s1
          將 s2 引用 s1 所引用的對象"Monday"

          第二段程序中,使用了 new 操作符,他明白的告訴程序:
          “我要一個新的!不要舊的!”與是一個新的"Monday"Sting對象被創
          建在內存中。他們的值相同,但是位置不同,一個在池中游泳
          一個在岸邊休息。哎呀,真是資源浪費,明明是一樣的非要分開做什么呢?

          4. 繼續潛水
          再次更改程序:
          public class TestString {
          public static void main(String[] args) {
          String s1 = "Monday";
          String s2 = new String("Monday");
          s2 = s2.intern();
          if (s1 == s2)
          System.out.println("s1 == s2");
          else
          System.out.println("s1 != s2");
          if (s1.equals(s2))
          System.out.println("s1 equals s2");
          else
          System.out.println("s1 not equals s2");
          }
          }
          這次加入:s2 = s2.intern();
          哇!程序輸出:
          s1 == s2
          s1 equals s2
          原來,程序新建了 s2 之后,又用intern()把他打翻在了池里
          哈哈,這次 s2 和 s1 有引用了同樣的對象了
          我們成功的減少了內存的占用

          5. == 與 equals() 的爭斗
          String 是個對象,要對比兩個不同的String對象的值是否相同
          明顯的要用到 equals() 這個方法
          可是如果程序里面有那么多的String對象,有那么多次的要用到 equals ,
          哦,天哪,真慢啊
          更好的辦法:
          把所有的String都intern()到緩沖池去吧
          最好在用到new的時候就進行這個操作
          String s2 = new String("Monday").intern();
          嗯,大家都在水池里泡著了嗎?哈哈
          現在我可以無所顧忌的用 == 來比較 String 對象的值了
          真是爽啊,又快又方便!



          看看 String 這一次又怎么鬧事兒吧
          1. 回顧一下壞脾氣的 String 老弟
          例程1:
          class Str {
              public static void main(String[] args) {
                  String s = "Hi!";
                  String t = "Hi!";
                  if (s == t)
                      System.out.println("equals");
                  else
                       System.out.println("not equals");
              }
          }
          程序輸出什么呢?
            程序輸出:equals
          2. 哦,天哪,它又在攪混水了
          例程2:
          class Str {
              public static void main(String[] args) {
                  String s = "HELLO";
                  String t = s.toUpperCase();
                  if (s == t)
                      System.out.println("equals");
                  else
                      System.out.println("not equals");
              }
          }
          那么這個程序有輸出什么呢?
          慎重!再慎重!不要被 String 這個迷亂的家伙所迷惑!
          它輸出:equals
                    WHY!!!
          把程序簡單的更改一下:
          class Str2 {
              public static void main(String[] args) {
                  String s = "Hello";
                  String t = s.toUpperCase();
                  if (s == t)
                      System.out.println("equals");
                  else
                      System.out.println("not equals");
              }
          }
          你可能會說:不是一樣嗎?不!千真萬確的,不一樣!這一次輸出:
          not equals  Oh MyGOD!!!
          誰來教訓一下這個 String 啊!
          3. 你了解你的馬嗎?
          “要馴服脫韁的野馬,就要了解它的秉性”牛仔們說道。
          你了解 String 嗎?解讀 String 的 API ,可以看到:toUpperCase() 和 toLowerCase() 方法返回一個新的String對象,它將原字符串表示字符串的大寫或小寫形勢;但是要注意:如果原字符串本身就是大寫形式或小寫形式,那么返回原始對象。這就是為什么第二個程序中 s 和 t 糾纏不清的緣故對待這個淘氣的、屢教不改的 String ,似乎沒有更好的辦法了讓我們解剖它,看看它到底有什么結構吧:
          (1) charAt(int n) 返回字符串內n位置的字符,第一個字符位置為0,最后一個字符的位置為length()-1,訪問錯誤的位置會扔出一塊大磚頭:StringIndexOutOfBoundsException 真夠大的
          (2) concat(String str) 在原對象之后連接一個 str ,但是返回一個新的 String 對象
          (3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法這個方法的實質是首先調用靜態字符方法toUpperCase() 或者 toLowerCase() 將對比的兩個字符轉換,然后進行 == 運算
          (4) trim() 返回一個新的對象,它將原對象的開頭和結尾的空白字符切掉同樣的,如果結果與原對象沒有差別,則返回原對象
          (5) toString() String 類也有 toString() 方法嗎?真是一個有趣的問題,可是如果沒有它,你的 String 對象說不定真的不能用在System.out.println() 里面啊小心,它返回對象自己String 類還有很多其他方法,掌握他們會帶來很多方便也會有很多困惑,所以堅持原則,是最關鍵的
          4. 我想買一匹更好的馬來購買更馴服溫和的 String 的小弟 StringBuffer 吧
          這時候會有人反對:
          它很好用,它效率很高,它怎么能夠是小弟呢?
          很簡單,它的交互功能要比 String 少,如果你要編輯字符串它并不方便,你會對它失望但這不意味著它不強大public final class String implements Serializable, Comparable, CharSequencepublic final class StringBuffer implements Serializable, CharSequence很明顯的,小弟少了一些東東,不過這不會干擾它的前途StringBuffer 不是由 String 繼承來的不過要注意兄弟它也是 final 啊,本是同根生看看他的方法吧,這么多穩定可靠的方法,用起來比頑皮的 String 要有效率的多? Java 為需要改變的字符串對象提供了獨立的 StringBuffer 類它的實例不可變(final),之所以要把他們分開是因為,字符串的修改要求系統的開銷量增大,占用更多的空間也更復雜,相信當有10000人擠在一個狹小的游泳池里游泳而岸邊又有10000人等待進入游泳池而焦急上火又有10000人在旁邊看熱鬧的時候,你這個 String 游泳池的管理員也會焦頭爛額在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了,而當要頻繁的更改字符串的內容的時候,就要借助于宰相肚里能撐船的StringBuffer 了
          5. 宰相肚里能撐船
          (1) length() 與 capacity()String 中的 length() 返回字符串的長度兄弟 StringBuffer 也是如此,他們都由對象包含的字符長度決定capacity()呢?
          public class TestCapacity {
              public static void main(String[] args){
               StringBuffer buf = new StringBuffer("it was the age of wisdom,");
                 System.out.println("buf = " + buf);
                  System.out.println("buf.length() = " + buf.length());
                  System.out.println("buf.capacity() = " + buf.capacity());
                  String str = buf.toString();
                  System.out.println("str = " + str);
                  System.out.println("str.length() = " + str.length());
                  buf.append(" " + str.substring(0,18)).append("foolishness,");
                  System.out.println("buf = " + buf);
                  System.out.println("buf.length() = " + buf.length());
                  System.out.println("buf.capacity() = " + buf.capacity());
                 System.out.println("str = " + str);
             }
          }

          程序輸出:
          buf = it was the age of wisdom.buf.length() = 25
          buf.capacity() = 41
          str = it was the age of wisdomstr.length() = 25
          buf = it was the age of wisdom, it was the age of foolishness,
          buf.length() = 56
          buf.capacity() = 84
          str = it was the age of wisdom,

          可以看到,在內容更改之后,capacity也隨之改變了長度隨著向字符串添加字符而增加而容量只是在新的長度超過了現在的容量之后才增加StringBuffer 的容量在操作系統需要的時候是自動改變的程序員們對capacity所能夠做的僅僅是可以在初始化 StringBuffer對象的時候。


          轉載自:http://www.leadbbs.com/a/a.asp?B=222&ID=1419085
          posted @ 2008-12-07 08:21 天長 閱讀(168) | 評論 (0)編輯 收藏
           
          為了讓equals方法來判斷2個對象的內容是否相同。
          重寫了equals方法。

          class Test2 {
              
          public static void main(String args[]) {
                  Dog d1 
          = new Dog(1);
                  Dog d2 
          = new Dog(1);
                  Dog d3 
          = new Dog(2);
                  System.out.println(d1 
          == d2);//false
                  System.out.println(d1.equals(d2));//true
                  System.out.println(d1.equals(d3));//false
              }
          }

          class Dog {
              
          private int i;
              Dog(
          int i) {
                  
          this.i = i;
              }
              
          public boolean equals(Object o) {
                  
          if(o != null) {
                      
          if(o instanceof Dog) {  //判斷傳過來的 對象o 是否屬于Dog類型的
                          Dog d = (Dog)o;  //把對象o強制轉換成Dog對象類型
                          if(this.i == d.i) {
                              
          return true;
                          }
                      }
                  }
                  
          return false;
              }
          }
          posted @ 2008-12-07 07:15 天長 閱讀(365) | 評論 (0)編輯 收藏
           

          我有很多概念都沒明白,現在反過頭來認識。

          Object是所有類的父類。
          java.lang.String也是繼承自java.lang.Object中。

          先比較一下2個類的toString()、equals()、= = (很多面試題都有),再來說一下String 的特殊。

          2個類toString()的比較:

          class Test {
              
          public static void
           main(String [] args) {
                  Object obj 
          = new
           Object();
                  Dog d 
          = new
           Dog();
                  String s 
          = new String("abc"
          );
                  
                  System.out.println(
          "obj = " +
           obj);    
                  System.out.println(
          "d = " +
           d);
                  System.out.println(
          "s = " +
           s);
              }
          }

          class
           Dog {}

          結果:

          obj 
          =
           java.lang.Object@c17164
          =
           Dog@1fb8ee3
          =
           abc


          查閱API文檔:

          Object類的 public String toString()   returns  
                              getClass().getName() 
          + '@' +
           Integer.toHexString(hashCode())
          String類的  
          public
           String toString()   returns  
                                the string itself.


          說明String類重寫了Object的toString方法。

          2個類equals()、= =比較:

          class Test {
              
          public static void
           main(String [] args) {
                  
                  
          //比較equals()和==

                  Dog d1 = new Dog(1);
                  Dog d2 
          = new Dog(1
          );
                  
                  System.out.println(
          "d1 == d2 " + (d1 == d2)); //false

                  System.out.println("d1.equals(d2) " + d1.equals(d2)); //false
                  
                  String s1 
          = new String("abc"
          );
                  String s2 
          = new String("abc"
          );
                  String s3 
          = "abc"
          ;
                  
                  System.out.println(
          "s1 == s2 " + (s1 == s2)); //false

                  System.out.println("s1.equals(s2) " + s1.equals(s2)); //ture
                  
                  System.out.println(
          "s1 == s3 " + (s1 == s3)); //false

                  System.out.println("s1.equals(s3) " + s1.equals(s3)); //true
              }
          }

          class
           Dog {
              
          private int
           i;
              Dog(){}
              Dog(
          int
           i){
                  
          this.i =
           i;
              }
          }

           

          "=="是比較2個對象的引用是否指向同一個地址,如果是比較2個基本類型,那么就是比較2個值是否相等。
          我new了2個Dog類,他們2個對象的棧引用肯定不能指向同一個堆地址。第二個String對象"=="的比較也是同樣道理。所以都返回了false(第三個比較體現了String的特殊類,等下說明)。

          查閱jdk的源代碼:"equals"在Object中定義為

          public boolean equals(Object obj) {
              
          return (this ==
           obj);
          }

          這就表示一個類如果沒有重寫該方法的話,它就是比較兩個的引用是否指向了同一個地址(和"=="比較是一致的)。
          類庫里的類基本都重寫的該方法,所以是比較2個對象的內容是否一樣的(String方法重寫了該方法,所以第二個equals比較返回ture),對于外面自己自定義的類,則需要自己重寫該方法來達到內容是否相等的邏輯。


          特殊對象String的equals()、= =比較

          String s = newString("abc");和String s = "abc";
          首先2個對象在內存分布上是不一樣的。第2個對象是s的棧引用指向數據片段區的地址(存放字符串常量,靜態成員變量)。第1個new出來的對象是s的棧引用指向堆中的地址(存放在堆中)。通過API文檔:新創建的字符串對象s是該參數字符串("abc")的副本。

          所以如代碼所表示:"=="比較是不一樣的,equals方法由于String重寫了,比較是字符序列。

           

          String s1 = "abc"    和  String s2 = "abc"比較;

          "=="和equals方法都返回ture;
          s1分配了字符常量"abc",那么再有"abc"要引用給對象,都不會再分配內存空間了。
          所以s1 和s2 指向的空間相同,內容也相同。

          posted @ 2008-12-06 08:53 天長 閱讀(1626) | 評論 (1)編輯 收藏
           
          主站蜘蛛池模板: 德江县| 余庆县| 琼中| 牙克石市| 丰镇市| 罗山县| 隆林| 金阳县| 阿克苏市| 三都| 澄江县| 鹤壁市| 海林市| 化德县| 巧家县| 泸溪县| 东宁县| 白银市| 乡城县| 呼图壁县| 河源市| 鄂伦春自治旗| 玉山县| 米林县| 明水县| 汝城县| 甘肃省| 迁安市| 环江| 海门市| 竹山县| 兴国县| 平凉市| 类乌齐县| 大宁县| 青龙| 三原县| 县级市| 宁远县| 盘锦市| 都江堰市|