一.爲何要使用Static關鍵字?編程
這裏摘錄一下《Java編程思想(第四版)》裏關於static關鍵字的一段原話:(P29)一般來講,當建立類時,就是在描述那個類的對象的外觀與行爲。除非用new建立那個對象,不然,實際上並未得到任何對象。執行new來建立對象的時候,數據存儲空間才被分配,其方法才供外界調用。有兩種情形用上述方法是沒法解決的。一種情形是,只想爲某特定域分配單一存儲空間,而不去考慮究竟要建立多少個對象,甚至根本不須要建立任何對象。另外一種情形是,但願某個方法不與包含他的類的任何對象關聯在一塊兒。也就是說,即便沒有建立對象,也可以調用方法。簡單來講,static的主要目的就是建立獨立於具體對象的域變量與方法。jvm
二.加了Static關鍵字修飾會有什麼不一樣?this
1.this不能調用被static修飾的屬性字段。spa
由於被static修飾的會在類加載的時候初始化,被稱爲類級變量(屬於類);而類的實例是在運行的時候初始化,屬於對象級變量(屬於對象)。指針
this是指當前對象的實例,super是指父類對象的實例。this(super)不能調用被static修飾的屬性字段的緣由:jvm有類加載器,第一次加載時執行static域,jvm會專門劃分一個內存區域給static程序塊,因此何時均可以調用這個被static修飾的屬性字段或者方法,屬於類。this指針是指向類的對象,在實例化對象時候jvm會在堆區分配給一個具體對象,this指向該對象。因此在靜態方法中不能調用非靜態屬性或者方法,若是在靜態方法中使用this關鍵字,則this沒法指向合適的對象。(通俗一點的話:即jvm的類加載機制決定了加載靜態會先與非靜態,即加載靜態的時候非靜態屬性和方法都不存在)code
2.static修飾屬性和方法對象
1.static修飾屬性時候,即全部該類對象共享一份存儲空間。blog
public class StaticTest { public static int staticA; public int A; public static void main(String[] args){ StaticTest test; StaticTest A1=new StaticTest(); StaticTest A2=new StaticTest(); A1.staticA++; A2.staticA++; A1.A++; A2.A++; System.out.println("StaticAInfo:"+A1.staticA+" "+A2.staticA); System.out.println("AInfo"+A1.A+" "+A2.A); } } /** 運行結果 * StaticAInfo:2 2 * AInfo1 1 **/
即static修飾的不是某個具體對象全部,而是該類全部對象共有的,StaticTest.staticA只有一份存儲空間。內存
2.static修飾方法時候,類和對象都能調用該方法,沒有被static修飾的方法只能被實例化對象調用。資源
public class StaticTest { public static void staticTest(){ } public void test(){ } public static void main(String[] args){ StaticTest.staticTest(); //StaticTest.test(); 該調用是錯誤的 StaticTest test=new StaticTest(); test.staticTest(); test.test(); } }
static修飾成員方法最大的做用,就是可使用"類名.方法名"的方式操做方法,避免了先要new出對象的繁瑣和資源消耗,一個static修飾的類中,不能使用非static修飾的成員變量和方法,這很好理解,由於static修飾的方法是屬於類的,若是去直接使用對象的成員變量,它會不知所措(不知該使用哪個對象的屬性)。
static修飾成員方法的時候最大的好處是能夠節省new一個對象的開銷,便可以直接經過類來調用方法。
通常用的比較少只能用來修飾內部類,一個static修飾的內部類中,不能使用非static修飾的成員變量和方法,這很好理解,由於static修飾的方法是屬於類的,若是去直接使用對象的成員變量,它會不知所措(不知該使用哪個對象的屬性)。
class Book{ public Book(String msg) { System.out.println(msg); } } public class Person { Book book1 = new Book("book1成員變量初始化"); static Book book2 = new Book("static成員book2成員變量初始化"); public Person(String msg) { System.out.println(msg); } Book book3 = new Book("book3成員變量初始化"); static Book book4 = new Book("static成員book4成員變量初始化"); public static void funStatic() { System.out.println("static修飾的funStatic方法"); } public static void main(String[] args) { Person.funStatic(); System.out.println("****************"); Person p1 = new Person("p1初始化"); } /**Output * static成員book2成員變量初始化 * static成員book4成員變量初始化 * static修飾的funStatic方法 * *************** * book1成員變量初始化 * book3成員變量初始化 * p1初始化 *///~ }
在上面的例子中咱們能夠發現兩個有意思的地方,第一個是當咱們沒有建立對象,而是經過類去調用類方法時,儘管該方法沒有使用到任何的類成員,類成員仍是在方法調用以前就初始化了,這說明,當咱們第一次去使用一個類時,就會觸發該類的成員初始化。第二個是當咱們使用了類方法,完成類的成員的初始化後,再new該類的對象時,static修飾的類成員沒有再次初始化,這說明,static修飾的類成員,在程序運行過程當中,只須要初始化一次便可,不會進行屢次的初始化。
class Book{ public Book(String msg) { System.out.println(msg); } } public class Person { Book book1 = new Book("book1成員變量初始化"); static Book book2; static { book2 = new Book("static成員book2成員變量初始化"); book4 = new Book("static成員book4成員變量初始化"); } public Person(String msg) { System.out.println(msg); } Book book3 = new Book("book3成員變量初始化"); static Book book4; public static void funStatic() { System.out.println("static修飾的funStatic方法"); } public static void main(String[] args) { Person.funStatic(); System.out.println("****************"); Person p1 = new Person("p1初始化"); } /**Output * static成員book2成員變量初始化 * static成員book4成員變量初始化 * static修飾的funStatic方法 * *************** * book1成員變量初始化 * book3成員變量初始化 * p1初始化 *///~ }