John Jiang

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

             :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          Java Weed
          平時在學習、應用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方法用于比較兩個對象是否在同一個地址。但Object的子類會重載這個方法,所以其它類中的equals方法的功能可能就會不一樣了。

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

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

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

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

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

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

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

          創建java.util.Date對象
          由于該類中的方法不利于日期的國際化,所以它的很多構造函數與方法都被deprecated了。這些相應的功能已經由java.util.Calendar提供。一般可以使用如下方法來創建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
          曾經在使用RMI時,遇到過拋該異常的情況。當時是由于我的Remote類中的一個方法的返回值是“不可序列化”的。
          具體情況就是,在設計的遠程接口(該接口繼承自java.rmi.Remote)中有一個方法的返回值是java.sql.ResultSet,但ResultSet對象是不可序列化的。因為ResultSet沒有繼承Serializable,而ResultSet的實現類又沒有實現
          Serializable 接口,那么ResultSet對象自然就不可序列化。
          解決方法就是,將返回值更換成可被序列化的對象,如String。

          從jar中讀文件
          要讀取jar中的文件,不能使用一般的創建InputStream實例之類的方法,因為InputStream沒有這個能力。而需要將這個文件作為“資源”進行讀取,即使用方法Class.getResourceAsStream(String name),請參見該方法的API文檔
          。下面會使用一個例子來描述。
          假設有一個Eclipse Java工程Test,它的目錄結構如下所示(Test是工程的根目錄,src是源代碼目錄,bin是編譯后的class文件的輸出目錄):
          Test
            |--src
                |--test
                    |--in
                        |--files
                            |--file.txt
                        |--FileInJar.java
            |--bin
                |--test
                    |--in
                        |--files
                            |--file.txt
                        |--FileInJar.class
          之所以使用這種工程目錄布局,就為了在程序開發的階段,就造成一種包結構的假象。即bin下的文件將可能會被打包到jar中,所以對于bin中的文件,Eclipse將會把它作為jar中的文件對待。如果src中存在非Java文件(此處是file.txt),Eclipse就會按該文件在src中的目錄結構將它直接拷貝到bin目錄中。FileInJar.java的完整內容如下:
          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中的內容讀出,然后顯示到標準輸出流(控制臺)中。
          請大家一定要注意path變量的值,它關系到Class.getResourceAsStream(String name)是否能夠找到該文件,否則它返回的InputStream將為null。
          現在將重點討論文件路徑的寫法,在討論之前必須要看看API文檔中關于路徑算法的內容:
          * 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')開頭,那么這個路徑就是相對于jar文件的根目錄,而與class文件(如示例中的FileInJar.class)在jar文件中的位置無關;[2]對于其它情況,這個路徑將相對于class文件在jar文件中的位置,實際上也就是包名后再加給出的name值(
          modified_package_name/name )。 對這兩種路徑格式的總結:[1]以'/'開頭,路徑就是指定文件在jar中的絕對路徑;[2]不以'/'開頭,路徑就是指定文件在jar中針對class文件的相對路徑。
          針對上述描述,原程序中的路徑還有另一種以'/'開頭的寫法: /test/in/files/file.txt。這種格式與原path的格式完全一樣:FileInJar.class在包test.in('.'將被轉換為'/')中,而給出的name(即path)值為files/file.txt,根據文檔中的算法 modified_package_name/name 示例程序中getResourceAsStream方法實際上仍然是根據路徑/test/in/files/file.txt來查找資源的(廢話! ^_^)。
          關于使用使用ClassLoader.getResourceAsStream(String name)
          細心的朋友可以發現,在ClassLoader中也有一個getResourceAsStream方法,而且它的功能同樣也是根據給定的name值來查找資源并返回一個InputStream對象。其實Class.getResourceAsStream(String)是
          ClassLoader.getResourceAsStream(String)的代理方法,但它會對name值做一些處理再傳遞給ClassLoader。如果直接將name值傳遞給ClassLoader中的這個方法,可能會找不到資源(盡管你的路徑沒有寫錯)。因為Class會對name值作一些處理(其實就是按前面所講的路徑算法進行處理),但ClassLoader并不會怎么做。對于這一點,JDK文檔中沒有明確的描述。
          注意:不建議直接使用ClassLoader中的相應方法。
          另外可以嘗試一下java.util.jar,該包用于讀/寫jar內文件。

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

          Bob Lee創新的一種Singleton實現方式

              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不能正常協作的問題
          在一個只允許上下滾動(HORIZONTAL_SCROLLBAR_NEVER)的ScrollPane中有一個Container,它使用FlowLayout,那么在默認情況下,當該container中各組件寬度之和已超出了ScrollPane的寬度時,并不會自動換行。這算是JDK的一個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中讀文件
          終于找你了!太感謝了!!!
          希望能以后繼續向牛人學習!!
          聯系方式:QQ:59477844  回復  更多評論
            

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

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

          主站蜘蛛池模板: 兴文县| 刚察县| 华亭县| 绥棱县| 馆陶县| 漯河市| 和平区| 益阳市| 马公市| 岢岚县| 上栗县| 揭阳市| 桃江县| 宜阳县| 桂平市| 汝阳县| 平舆县| 明光市| 文安县| 土默特右旗| 霍州市| 岫岩| 老河口市| 开远市| 胶南市| 中西区| 雷山县| 桐乡市| 灵台县| 乳山市| 尖扎县| 永春县| 湄潭县| 视频| 仙居县| 道孚县| 通渭县| 柳河县| 武穴市| 自治县| 旺苍县|