John Jiang

          a cup of Java, cheers!
          https://github.com/johnshajiang/blog

             :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          Java Weed
          平時(shí)在學(xué)習(xí)、應(yīng)用Java的過程中,遇到的一些小知識,將它們收集到這里。雜草(weed)也不能丟棄嘛。(2009.09.16最后更新)

          Primitive Data Type
           boolean(2)  
           byte(8)  
           char(16)  short(16) 
           int(32)   float(32)
           long(64)  double(64) 


          All Possible Combinations of Features and Modifers
           Modifer  Class  Variable Method  Constructor  FreeFloating Block 
           public
          yes yes yes  yes  no
          protected  no yes yes yes no
          (default)
          yes yes yes yes yes
          private  no yes yes yes no
          final  yes yes yes no no
          abstract  yes no yes no no
           static no  yes  yes  no  yes 
          native  no no yes no no
          transient  no yes no no no
          volatile  no yes no no no
          synchronized  no no yes no yes

          Priority of Operators
           一  +  -  ++  --  !  ~
           元 new  (type) 
           二 *  /  % 
           | +  - 
           | <<  >>  >>> 
           |  <  >  <=  >=
            |
           ==  !=
            |
            |
           ^
            |
           |
            |
           &&
           元  ||
           三元  ? :
           賦  =  *=  /=  %=  +=  -=  <<=
           值  >>=  >>>=  &=  ^=  |=

          Object中的equals方法用于比較兩個(gè)對象是否在同一個(gè)地址。但Object的子類會重載這個(gè)方法,所以其它類中的equals方法的功能可能就會不一樣了。

          初始化(Initialization)
          闡述對象被創(chuàng)建時(shí)的若干步驟,假設(shè)以類Dog為例。
          [1]當(dāng)首次創(chuàng)建類型Dog的對象時(shí)(構(gòu)造器可以看成靜態(tài)方法),或者Dog類的靜態(tài)方法/靜態(tài)字段首次被訪問時(shí),Java解釋器必須查找類路徑,以定位Dog.class文件。
          [2]然后載入Dog.class(這將創(chuàng)建一個(gè)Class對象),有關(guān)靜態(tài)初始化的所有動作都會執(zhí)行。故,靜態(tài)初始化只在Class對象首次加載的時(shí)候進(jìn)行一次。
          [3]當(dāng)用new Dog()創(chuàng)建對象的時(shí)候,首次將在堆上為Dog對象分配足夠的存儲空間。
          [4]這塊存儲空間被清零,就自動地將Dog對象中的所有基本數(shù)據(jù)都設(shè)置成了缺省值,而引用則被設(shè)置成了null。
          [5]執(zhí)行所有出現(xiàn)于字段定義處的初始化動作。
          [6]執(zhí)行構(gòu)造器。

          多態(tài)(Polymophsim)
          private方法屬于final方法。只有非private方法才可以被覆蓋;在子類中,對于其基類中的private方法,最好采用不同的名字。
          類X可以從它的直接父類(接口)中繼承它的所有non-private的,并且沒有被類X覆蓋(override)和隱藏的方法(無論它是不是abtract)。
          構(gòu)造器并不具有多態(tài)性,它實(shí)際上是static方法。除了在構(gòu)造器內(nèi),禁止在其它地方調(diào)用構(gòu)造器。

          構(gòu)造器調(diào)用順序
          [1]在任何事情發(fā)生之前,將分配給對象的存儲空間初始化為二進(jìn)制的零。
          [2]調(diào)用該類的父類構(gòu)造器。這個(gè)步驟會不斷地反復(fù)遞歸下去,首先是調(diào)用這種層次結(jié)構(gòu)的根的構(gòu)造器,然后是下一層子類,...,直到最低層的子類。
          [3]按聲明順序調(diào)用該類的成員的初始化方法。
          [4]調(diào)用該類的構(gòu)造器的主體。

          編寫構(gòu)造器的一條有效準(zhǔn)則
          用盡可能簡單的方法使對象進(jìn)入正常狀態(tài);如果可以的話,避免調(diào)用其他方法。在構(gòu)造器中唯一能夠安全調(diào)用的方法是基類中的final,private(自動屬于fianl方法),因?yàn)檫@些方法不會被覆蓋。
          class Dad {
              String name = "Dad";
          }
          class Son extends Dad {
              String name = "Son";
          }
          Son 的每一個(gè)對象將會有兩個(gè)field "name",一個(gè)是類Dad中的"name",另一個(gè)是類Son中的"name"。具體用哪個(gè)一個(gè)"name",則將由引用變量的類型來決定。即,對于 Dad x = new Son(); x.name引用的是類Dad中的"name "("Dad");如果是Son x = new Son(); x.name,很顯然引用的是類Son中的"name"。而對于方法,則僅用override原理來處理即可。

          Set 的使用
          實(shí)際上Set就是Collection,只是行為不同。這是繼承與多態(tài)的典型應(yīng)用:表現(xiàn)不同的行為。
          使用HashSet
          必須為類定義equals()方法和hashCode()方法; 使用TreeSet時(shí)必須為類定義equals()方法。但作為一種編程風(fēng)格,在覆蓋equals()時(shí),也要覆蓋hashCode()。

          正則表達(dá)式 (Regular Expression)
          lookingAt()和matches()只有在輸入的最開始處就與RE匹配時(shí)才會成功(true);matches()只有在整個(gè)輸入都與RE匹配時(shí) 才會成功,而lookingAt()只要求輸入的第一部分與RE匹配就會成功。(Bruce認(rèn)為這幾個(gè)方法名不是很直觀?。?br />
          如何使JTable中的列不能被移動?
          使用方法JTable.getTableHeader().setReorderingAllowed(false),即可使用戶不能拖動表中的各個(gè)列。

          改變GUI的Look&Feel后,需要更新GUI組件
          SwingUtilities.updateComponentTreeUI(java.awt.Component)

          創(chuàng)建java.util.Date對象
          由于該類中的方法不利于日期的國際化,所以它的很多構(gòu)造函數(shù)與方法都被deprecated了。這些相應(yīng)的功能已經(jīng)由java.util.Calendar提供。一般可以使用如下方法來創(chuàng)建java.util.Date對象:
          java.util.Calendar calendar = new java.util.Calendar();
          calendar.set(int year, int month, int date);
          java.util.Date date = calendar.getTime();


          UnmarshalException
          曾經(jīng)在使用RMI時(shí),遇到過拋該異常的情況。當(dāng)時(shí)是由于我的Remote類中的一個(gè)方法的返回值是“不可序列化”的。
          具體情況就是,在設(shè)計(jì)的遠(yuǎn)程接口(該接口繼承自java.rmi.Remote)中有一個(gè)方法的返回值是java.sql.ResultSet,但ResultSet對象是不可序列化的。因?yàn)镽esultSet沒有繼承Serializable,而ResultSet的實(shí)現(xiàn)類又沒有實(shí)現(xiàn)
          Serializable 接口,那么ResultSet對象自然就不可序列化。
          解決方法就是,將返回值更換成可被序列化的對象,如String。

          從jar中讀文件
          要讀取jar中的文件,不能使用一般的創(chuàng)建InputStream實(shí)例之類的方法,因?yàn)镮nputStream沒有這個(gè)能力。而需要將這個(gè)文件作為“資源”進(jìn)行讀取,即使用方法Class.getResourceAsStream(String name),請參見該方法的API文檔
          。下面會使用一個(gè)例子來描述。
          假設(shè)有一個(gè)Eclipse Java工程Test,它的目錄結(jié)構(gòu)如下所示(Test是工程的根目錄,src是源代碼目錄,bin是編譯后的class文件的輸出目錄):
          Test
            |--src
                |--test
                    |--in
                        |--files
                            |--file.txt
                        |--FileInJar.java
            |--bin
                |--test
                    |--in
                        |--files
                            |--file.txt
                        |--FileInJar.class
          之所以使用這種工程目錄布局,就為了在程序開發(fā)的階段,就造成一種包結(jié)構(gòu)的假象。即bin下的文件將可能會被打包到j(luò)ar中,所以對于bin中的文件,Eclipse將會把它作為jar中的文件對待。如果src中存在非Java文件(此處是file.txt),Eclipse就會按該文件在src中的目錄結(jié)構(gòu)將它直接拷貝到bin目錄中。FileInJar.java的完整內(nèi)容如下:
          package test.in;
          import java.io.InputStream;

          public class FileInJar {

              
          public static void main(String[] args) throws Exception {
                  FileInJar path 
          = new FileInJar();

                  String path
          = "files/file.txt";
                  InputStream in = path.getClass().getResourceAsStream(path);

                  
          int c;
                  
          while ((c = in3.read()) != -1) {
                      System.out.print((
          char) c);
                  }
              }
          }
          該程序就是將file.txt中的內(nèi)容讀出,然后顯示到標(biāo)準(zhǔn)輸出流(控制臺)中。
          請大家一定要注意path變量的值,它關(guān)系到Class.getResourceAsStream(String name)是否能夠找到該文件,否則它返回的InputStream將為null。
          現(xiàn)在將重點(diǎn)討論文件路徑的寫法,在討論之前必須要看看API文檔中關(guān)于路徑算法的內(nèi)容:
          * If the name begins with a '/'  ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
          * Otherwise, the absolute name is of the following form:

              modified_package_name/name
                    
          Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').

          Class.getResourceAsStream(String name)是通過name(即示例程序中的path)值來找資源的。對于name的值的格式,存在兩種情況:[1]以'/'(它的Unicode值為'\u002f')開頭,那么這個(gè)路徑就是相對于jar文件的根目錄,而與class文件(如示例中的FileInJar.class)在jar文件中的位置無關(guān);[2]對于其它情況,這個(gè)路徑將相對于class文件在jar文件中的位置,實(shí)際上也就是包名后再加給出的name值(
          modified_package_name/name )。 對這兩種路徑格式的總結(jié):[1]以'/'開頭,路徑就是指定文件在jar中的絕對路徑;[2]不以'/'開頭,路徑就是指定文件在jar中針對class文件的相對路徑。
          針對上述描述,原程序中的路徑還有另一種以'/'開頭的寫法: /test/in/files/file.txt。這種格式與原path的格式完全一樣:FileInJar.class在包test.in('.'將被轉(zhuǎn)換為'/')中,而給出的name(即path)值為files/file.txt,根據(jù)文檔中的算法 modified_package_name/name, 示例程序中g(shù)etResourceAsStream方法實(shí)際上仍然是根據(jù)路徑/test/in/files/file.txt來查找資源的(廢話! ^_^)。
          關(guān)于使用使用ClassLoader.getResourceAsStream(String name)
          細(xì)心的朋友可以發(fā)現(xiàn),在ClassLoader中也有一個(gè)getResourceAsStream方法,而且它的功能同樣也是根據(jù)給定的name值來查找資源并返回一個(gè)InputStream對象。其實(shí)Class.getResourceAsStream(String)是
          ClassLoader.getResourceAsStream(String)的代理方法,但它會對name值做一些處理再傳遞給ClassLoader。如果直接將name值傳遞給ClassLoader中的這個(gè)方法,可能會找不到資源(盡管你的路徑?jīng)]有寫錯(cuò))。因?yàn)镃lass會對name值作一些處理(其實(shí)就是按前面所講的路徑算法進(jìn)行處理),但ClassLoader并不會怎么做。對于這一點(diǎn),JDK文檔中沒有明確的描述。
          注意:不建議直接使用ClassLoader中的相應(yīng)方法。
          另外可以嘗試一下java.util.jar,該包用于讀/寫jar內(nèi)文件。

          final變量的初始化
          一般情況下,final變量都是在它的聲明處就進(jìn)行初始化,如下所示:
          class Foo {
             
          final int F = 10;
              void bar() {
                  final int BAR = 1;
                  System.out.println(BAR);
          }
          注:與一般的類成員變量不同,此處的變量F并不會進(jìn)行默認(rèn)的初始化(如果是默認(rèn)初始化,F(xiàn)的值應(yīng)該為0)。
          對類中的final成員變量,除上面的初始化方式,還可以在構(gòu)造器中對final變量進(jìn)行初始化,如下所示:
          class Foo {
             
          final int F;
              Foo() {
                  F 
          = 10;
              }
          }
          在使用上述方式時(shí),如果有多個(gè)構(gòu)造器,那么每個(gè)構(gòu)造器都必須對final成員變量進(jìn)行初始化,如下所示:
          class Foo {
             
          final int F;
              Foo() {
                  F 
          = 10;
              }
              Foo(
          int f) {
                  F 
          = f;
              }
              Foo(String str) {
                  F 
          = 0;
                  System.out.println(str);
              }
          }

          Bob Lee創(chuàng)新的一種Singleton實(shí)現(xiàn)方式

              public class Singleton {
                  static class SingletonHolder {
                      static Singleton instance = new Singleton();
                  }
                  public static Singleton getInstance() {
                      return SingletonHolder.instance;
                  }
              }


          解決使用JSplitPane.setDividerLocation(double d)無效的問題
          public class BaseSplitPane extends JSplitPane {

              
          private boolean isPainted = false;

              
          private boolean hasProportionalLocation = false;

              
          private double proportionalLocation = 0.0D;

              
          public BaseSplitPane() {
                  
          super();
              }

              
          public BaseSplitPane(int newOrientation, boolean newContinuousLayout,
                      Component newLeftComponent, Component newRightComponent) {
                  
          super(newOrientation, newContinuousLayout, newLeftComponent,
                          newRightComponent);
              }

              
          public BaseSplitPane(int newOrientation, boolean newContinuousLayout) {
                  
          super(newOrientation, newContinuousLayout);
              }

              
          public BaseSplitPane(int newOrientation, Component newLeftComponent,
                      Component newRightComponent) {
                  
          super(newOrientation, newLeftComponent, newRightComponent);
              }

              
          public BaseSplitPane(int newOrientation) {
                  
          super(newOrientation);
              }

              
          public void setDividerLocation(double proportionalLocation) {
                  
          if (!isPainted) {
                      hasProportionalLocation 
          = true;
                      
          this.proportionalLocation = proportionalLocation;
                  } 
          else
                      
          super.setDividerLocation(proportionalLocation);
              }

              
          public void paint(Graphics g) {
                  
          if (!isPainted) {
                      
          if (hasProportionalLocation)
                          
          super.setDividerLocation(proportionalLocation);
                      isPainted 
          = true;
                  }
                  
          super.paint(g);
              }
          }

          FlowLayout與ScrollPane不能正常協(xié)作的問題
          在一個(gè)只允許上下滾動(HORIZONTAL_SCROLLBAR_NEVER)的ScrollPane中有一個(gè)Container,它使用FlowLayout,那么在默認(rèn)情況下,當(dāng)該container中各組件寬度之和已超出了ScrollPane的寬度時(shí),并不會自動換行。這算是JDK的一個(gè)Bug,但在Sun官方論壇中給出了一種解決方案
          public class ScrollableFlowPanel extends JPanel implements Scrollable {

              
          private static final long serialVersionUID = -7723152015485080501L;

              
          public ScrollableFlowPanel(int alignment) {
                  
          super(new FlowLayout(alignment));
              }

              
          public ScrollableFlowPanel() {
                  
          this(FlowLayout.CENTER);
              }

              
          public void setBounds(int x, int y, int width, int height) {
                  
          super.setBounds(x, y, getWidth(), height);
              }

              
          public Dimension getPreferredSize() {
                  
          return new Dimension(getWidth(), getPreferredHeight());
              }

              
          public Dimension getPreferredScrollableViewportSize() {
                  
          return super.getPreferredSize();
              }

              
          public int getScrollableUnitIncrement(Rectangle visibleRect,
                      
          int orientation, int direction) {
                  
          int hundredth = (orientation == SwingConstants.VERTICAL ? getParent()
                          .getHeight() : getParent().getWidth()) 
          / 100;
                  
          return (hundredth == 0 ? 1 : hundredth);
              }

              
          public int getScrollableBlockIncrement(Rectangle visibleRect,
                      
          int orientation, int direction) {
                  
          return orientation == SwingConstants.VERTICAL ? getParent().getHeight()
                          : getParent().getWidth();
              }

              
          public boolean getScrollableTracksViewportWidth() {
                  
          return true;
              }

              
          public boolean getScrollableTracksViewportHeight() {
                  
          return false;
              }

              
          private int getPreferredHeight() {
                  
          int rv = 0;
                  
          for (int k = 0, count = getComponentCount(); k < count; k++) {
                      Component comp 
          = getComponent(k);
                      Rectangle r 
          = comp.getBounds();
                      
          int height = r.y + r.height;
                      
          if (height > rv)
                          rv 
          = height;
                  }
                  rv 
          += ((FlowLayout) getLayout()).getVgap();
                  
          return rv;
              }
          }

          updating...
          posted on 2006-08-12 09:04 John Jiang 閱讀(821) 評論(3)  編輯  收藏 所屬分類: JavaSE 、Java

          評論

          # re: Java Weed 2007-06-14 13:50 天天
          從jar中讀文件
          終于找你了!太感謝了!!!
          希望能以后繼續(xù)向牛人學(xué)習(xí)!!
          聯(lián)系方式:QQ:59477844  回復(fù)  更多評論
            

          # re: Java Weed 2007-06-14 13:51 天天
          說的很詳細(xì)啊!!
          再頂~  回復(fù)  更多評論
            

          # re: Java Weed 2007-06-14 15:46 Sha Jiang
          謝謝 :-D  回復(fù)  更多評論
            

          主站蜘蛛池模板: 棋牌| 新民市| 河津市| 上虞市| 讷河市| 景泰县| 华坪县| 皋兰县| 定远县| 监利县| 卢湾区| 洛南县| 古浪县| 房产| 黎城县| 嘉祥县| 浦县| 红安县| 西峡县| 井研县| 青川县| 老河口市| 吉水县| 长泰县| 体育| 岳阳县| 大名县| 甘谷县| 古田县| 绥德县| 本溪市| 东源县| 镇宁| 广元市| 合作市| 托克托县| 丘北县| 土默特右旗| 辽宁省| 怀来县| 邵武市|