java之static分析

對於學習static我們先來看兩個例子:
//Example 1  Tst.java,no main() method
   package com.blogchina.qb2049;
   public class Tst
   {
      static { System.out.println("111111"); } 
   }
運行結果爲: 111111
           Exception in thread "main" java.lang.NoSuchMethodError: main
同樣的道理看第二個例子:
//Example 2  TFrame.java,no main() method
  package com.blogchina.qb2049;
  import javax.swing.JFrame;
  public class TFrame
  {
    static {
               JFrame jfr_fr= new JFrame("無main()窗體 ");
               jfr_fr.setLocation(400,300);
               jfr_fr.setSize(200,300);
               jfr_fr.setVisible(true);
               jfr_fr.setDefaultCloseOperation(jfr_fr.EXIT_ON_CLOSE);
            } 
 }運行結果如下圖:
 

 
     這到底怎麼回事 ,這不和我們大多數教程 介紹的無main()方法程序似乎不能運行相矛盾嗎。其實,這其中的緣由 就在於那個static的修飾。我在學習java時,static的學習讓我很受啓發 ,特此把它的總結如下,希望對想學習java的朋友有所幫助。同時,本文中的不足還希望大家多多的提出來,我們共同學習。

學習本文你到底要學到什麼:
1、 static在java中到底代表什麼,爲何要用它?
2、 static在java中怎麼用?
3、 static 有那些特點和使用的“侷限”?


1、 static在java中到底代表什麼,爲何要用它?
     static――靜態――“指定位置“
     首先,我們來看看java的內存:java把內存分爲棧內存和堆內存,棧內存用來存放一些基本類型的變量和數組及對象的引用變量,而堆內存主要是來放置對象的。
      用 static的修飾的變量和方法,實際上是指定了這些變量和方法在內存中的“固定位置”-static storage。既然要有“固定位置”那麼他們的 “大小”似乎就是固定的了,有了固定位置和固定大小的特徵了,在棧中或堆中開闢空間那就是非常的方便了。如果靜態的變量或方法在不出其作用域的情況下,其 引用句柄是不會發生改變的。
      我們常看到:static變量有點類似於C中的全局變量的概念;靜態表示的是內存的共享,就是它的每一個 實例都指向同一個內存地址。把static拿來,就是告訴JVM它是靜態的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不 會變成原樣,你把它清理了,它就不會回來了。我們常可看到類似以下的例子來說明這個問題:
    class Student{
                static int numberOfStudents=0;
                Student()
                 {
                   numberOfStudents++;
                 }
               } 每一次創建一個新的Student實例時,成員numberOfStudents都會不斷的遞增,並且所有的Student實例都訪問同一個 numberOfStudents變量,實際上int numberOfStudents變量在內存中只存儲在一個位置上。爲了來更好的說明這個問題,我 特意學習張老師(張孝祥)使用一個形象的圖解:
            創建兩個Student實例,stu1=new Student(); stu2=new Student();    

              

             多個實例共享一個變量似乎不足以讓我們對static那麼的熱情,實際上java引入static卻有另外的含義:

      (1)、引用static的方法和變量,不需要和實例捆綁在一起,這可以提高代碼的編寫的效率,這樣的例子我們隨處可見;
      (2)、 java的主類中main()方法本身就是一個static的,所以main方法的執行就是在沒有產生新的實例的情況;對於靜態的東西,JVM在加載類 時,就在內存中開闢了這些靜態的空間,所以雖沒有靜態的main()方法但是程序還是執行了,不過拋出來了無main()方法的異常。這也不知算不算是 java的一個漏洞;
      (3)、如果需要創建一個脫離於實例的變量或方法(只與整個類有關),那麼用static作修飾是再好不過了,如我們經常看到要統計實例實現的個數(通常的例子就是計數)。
      (4)、使用一種靜態的方法的編程通常叫做防禦(defensive)編程,它可以在API供應商突然中斷支持的情況下保護代碼  


2、 static在java中怎麼用?
     使用static時,要記着我闡述的static代表什麼。
      static 使用非常的簡單,如果要修飾一個靜態塊只需:staic {……..}即可(常用靜態塊來初始化一些變量); 靜態方法就參照main()的形式:訪問標 識 static returnType method(…) {};靜態變量就是:static type fields;
     在使用靜態的方法時,可以直接用類名來引用,不需要創建實例(當然創建實例也是可以的),例如,System.out,String.valueOf()等等。

3、 static 有那些特點和使用的“侷限”?
     從上面的分析可知,static的東西在類加載時,就分配了內存空間,即編譯時就爲這些成員變量的實例分配了空間。
      那 麼在static塊內和方法體內,我們能給它放一個在內存中還沒有着落的變量?顯然與我們先前所說的相左。static的東西,人家是在 static storage中有“指定位置“的,如果我們茫然的在static的作用域中放置一個普通的變量,那麼編譯時JVM就毫不客氣的給你個異 常:
non-static variable a cannot be referenced from a static context或 non- static method Test() cannot be referenced from a static context(注:Test() 是我試驗時的一個例子 ),除非我在static中現場開闢空間,用new來要內存。
對於static的初始化問題,我們還是值得討論的。現看下面的例子:
//StaticInit show the static decorated initialization 
package com.blogchina.qb2049;
public class StaticInit
{
   static int i;
   int a;
   public StaticInit()
   {
      a=6;
      System.out.println("a 的初始化"+a);
   } 
   public static void main(String[] args)
  {
    new StaticInit();
  }
  static 
  {
     i=5;
     System.out.println("i 的初始化"+i);
  }
}運行結果如下:i 的初始化5
                        a 的初始化6
  靜態塊的初始化要早於非靜態的,原因就是在於這些東西是在類裝載時就開始初始化了。
      說 起static的“侷限“,總結起來就是:在static的方法中僅能夠調用其他的static方法和static變量;在static方法中不能以任何 方式引用this或super;static變量在定義時必須進行初始化,並且初始化的時間早於非靜態。還有一個侷限我需要具體的說明一下,static 的變量的初始化僅能一次,如下例:
    //Static.java, initialize only one
    class T1
    {   
     static int t=1;
     T1(int b)
     {
       t=b;
     }
   }
   public class Static
    {
       T1 t1=new T1(2);
       T1 t2=new T1(3);
       T1 t3=new T1(4);
       public Static()
       {
         System.out.println("t1: "+t1.t);
         System.out.println("t2: "+t2.t);
         System.out.println("t3: "+t3.t);
      }
      public static void main(String args[])
      {
        new Static();
      }
   }
運行結果爲: t1: 4
                        t2: 4
                        t3: 4

該static變量只是接受了最後一次的初始化.實際這還是我們先前提到的多個實例共享一個靜態的變量的問題。
總之,static就是給我們一個這樣的忠告:static的東西在編譯時,就已向內存要到了存取空間了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章