Java中的static
學習本文你到底要學到什么:
1、 static在java中到底代表什么,為何要用它?
2、 static在java中怎么用?
3、 static 有那些特點和使用的“局限”
1、 static在java中到底代表什么,為何要用它?
static――靜態――“指定位置“
首先,我們來看看java的內存:java把內存分為棧內存和堆內存,棧內存用來存放一些基本類型的變量和數組及對象的引用變量,而堆內存主要是來放置對象的。
用static的修飾的變量和方法,實際上是指定了這些變量和方法在內存中的“固定位置”-static storage。既然要有“固定位置”那么他們的“大小”似乎就是固定的了,有了固定位置和固定大小的特征了,在棧中或堆中開辟空間那就是非常的方便了。如果靜態的變量或方法在不出其作用域的情況下,其引用句柄是不會發生改變的。
我們常看到:static變量有點類似于C中的全局變量的概念;靜態表示的是內存的共享,就是它的每一個實例都指向同一個內存地址。把static拿來,就是告訴JVM它是靜態的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不會變成原樣,你把它清理了,它就不會回來了。我們常可看到類似以下的例子來說明這個問題:
package com.meritit.test; class Student { Student() { |
每一次創建一個新的Student實例時,成員numberOfStudents都會不斷的遞增,并且所有的Student實例都訪問同一個numberOfStudents變量,實際上int numberOfStudents變量在內存中只存儲在一個位置上。
多個實例共享一個變量似乎不足以讓我們對static那么的熱情,實際上java引入static卻有另外的含義:
(1)、引用static的方法和變量,不需要和實例捆綁在一起,這可以提高代碼的編寫的效率,這樣的例子我們隨處可見;
(2)、java的主類中main()方法本身就是一個static的,所以main方法的執行就是在沒有產生新的實例的情況;對于靜態的東西,JVM在加載類時,就在內存中開辟了這些靜態的空間,所以雖沒有靜態的main()方法但是程序還是執行了,不過拋出來了無main()方法的異常。這也不知算不算是java的一個漏洞;
(3)、如果需要創建一個脫離于實例的變量或方法(只與整個類有關),那么用static作修飾是再好不過了,如我們經常看到要統計實例實現的個數(通常的例子就是計數)。
(4)、使用一種靜態的方法的編程通常叫做防御(defensive)編程,它可以在API供應商突然中斷支持的情況下保護代碼
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的初始化問題,我們還是值得討論的。現看下面的例子
package com.meritit.test; public class StaticInit |
運行結果如下:
i 的初始化5
a 的初始化6
靜態塊的初始化要早于非靜態的,原因就是在于這些東西是在類裝載時就開始初始化了。
說起static的“局限“,總結起來就是:在static的方法中僅能夠調用其他的static方法和static變量;在static方法中不能以任何方式引用this或super;static變量在定義時必須進行初始化,并且初始化的時間早于非靜態。還有一個局限我需要具體的說明一下,static的變量的初始化僅能一次,如下例:
package com.meritit.test; public class Static { public Static() { public static void main(String args[]) { class T1 { T1(int b) { |
運行結果:
t1: 4
t2: 4
t3: 4
該static變量只是接受了最后一次的初始化.實際這還是我們先前提到的多個實例共享一個靜態的變量的問題。
總之,static就是給我們一個這樣的忠告:static的東西在編譯時,就已向內存要到了存取空間了。