一、static基本描述
對於關鍵字static ,大家應該不會陌生,因為一直編寫:
public static void main(String args[]) {...}
那static表示什麼呢。static表示“全域”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static代碼塊,但是要注意一點:Java語言中沒有全域變數的概念。
二、使用static定義屬性
我們先來看一個表示圖書的操作類,其中所有書的出版社都是清華出版社。
package com.wz.thisdemo;class Book { private String title; private double price; String pub = "清華大學出版社"; // 此處暫時不封裝 public Book(String title, double price) { super(); this.title = title; this.price = price; } public String getInfo() { return "書名:" + this.title + ",價格:" + this.price + ",出版社:" + this.pub; }}public class TestDemo { public static void main(String args[]) { Book ba = new Book("Java開發",10.2); Book bb = new Book("Android開發",11.2); Book bc = new Book("Oracle開發",12.2); System.out.println(ba.getInfo()); System.out.println(bb.getInfo()); System.out.println(bc.getInfo()); }}
運行結果:
書名:Java開發,價格:10.2,出版社:清華大學出版社書名:Android開發,價格:11.2,出版社:清華大學出版社書名:Oracle開發,價格:12.2,出版社:清華大學出版社
記憶體配置圖如下:
那麼問題來了,既然這個類中所有的圖書的出版社都是同一個,那麼每個圖示對象還有必要佔有重複的屬性資訊麼。
假設有1000萬個Book類對象,要求將所有對象的出版社名稱更換,意味著什麼。
我們看代碼,在主方法中添加如下:
public class TestDemo { public static void main(String args[]) { Book ba = new Book("Java開發",10.2); Book bb = new Book("Android開發",11.2); Book bc = new Book("Oracle開發",12.2); ba.pub = "北京大學出版社"; bb.pub = "浙江大學出版社"; System.out.println(ba.getInfo()); System.out.println(bb.getInfo()); System.out.println(bc.getInfo()); }}
運行結果:
書名:Java開發,價格:10.2,出版社:北京大學出版社書名:Android開發,價格:11.2,出版社:浙江大學出版社書名:Oracle開發,價格:12.2,出版社:清華大學出版社
這意味著要修改1000萬個對象的內容。所以,如果將對象的屬性定義為普通屬性,這就意味著每一塊堆記憶體空間都將儲存著各自的資訊。
既然每個Book類對象的pub內容是一樣的,那麼應該將其定義為一個共用的屬性,即所有的對象都共用pub屬性。於是,在這種情況下為了描述共用的概念,可以使用static來定義需要共用的這個屬性。
在Book類的屬性pub上使用static修飾:
static String pub = "清華大學出版社";
主方法為:
public class TestDemo { public static void main(String args[]) { Book ba = new Book("Java開發",10.2); Book bb = new Book("Android開發",11.2); Book bc = new Book("Oracle開發",12.2); ba.pub = "北京大學出版社"; System.out.println(ba.getInfo()); System.out.println(bb.getInfo()); System.out.println(bc.getInfo()); }}
運行結果:
書名:Java開發,價格:10.2,出版社:北京大學出版社書名:Android開發,價格:11.2,出版社:北京大學出版社書名:Oracle開發,價格:12.2,出版社:北京大學出版社
我們發現,一旦屬性定義上使用了static 之後,只要有一個對象修改了屬性的內容,那麼所有的對象的這個static屬性的內容都一起進行修改。此時,pub屬性就成了一個公用屬性。
於是,記憶體配置圖也變成了如下這樣:
static聲明的屬性與普通屬性(非static)最大的區別就是:儲存記憶體地區的不同。
還有一個問題:既然static定義的屬性是公用屬性,那麼如果只是簡單的由一個對象去修改這個屬性的做法是不合適的。合適的做法就是由所有對象的公用代表 — 類來修改,通過“類名稱.static屬性”的方式來完成。
所以以上的:
ba.pub = "北京大學出版社";
最好用
Book.pub = "北京大學出版社";
來代替。
通過以上說明, 我們應該清楚以下幾點:
(1)使用static定義的屬性不在堆記憶體之中儲存,儲存在全域資料區;
(2)使用static定義的屬性工作表示類屬性,類屬性可以由類名稱直接進行調用;
(3)static屬性雖然定義在類中,但是其可以在沒有執行個體化對象的時候進行調用(普通屬性儲存在堆記憶體裡,而static屬性儲存在全域資料區之中);
那麼在定義屬性的時候,什麼時候使用static定義。什麼時候不使用static定義呢。
在開發中,盡量不使用static定義屬性,如果需要描述共用資訊的時候,才使用static定義()主要是為了方便集體修改,且不重複分配記憶體空間)。
三、使用static定義方法
除了使用static定義屬性之外,方法上也可以使用static進行定義,那麼很明顯,使用static定義的方法也可以在沒有執行個體化對象產生的情況下由類名稱直接進行調用。
來看一段代碼:
package com.wz.thisdemo;class Book { private String title; private double price; private static String pub = "清華大學出版社"; public Book(String title, double price) { this.title = title; this.price = price; } //static方法 public static void setPub(String p){ pub = p; } public String getInfo() { return "書名:" + this.title + ",價格:" + this.price + ",出版社:" + this.pub; }}public class TestDemo { public static void main(String args[]) { //在對象產生前進行調用 Book.setPub("北京大學出版社"); Book ba = new Book("Java開發",10.2); Book bb = new Book("Android開發",11.2); Book bc = new Book("Oracle開發",12.2); System.out.println(ba.getInfo()); System.out.println(bb.getInfo()); System.out.println(bc.getInfo()); }}
運行結果:
書名:Java開發,價格:10.2,出版社:北京大學出版社書名:Android開發,價格:11.2,出版社:北京大學出版社書名:Oracle開發,價格:12.2,出版社:北京大學出版社
但是問題來了,類中的方法有兩種,一種是static方法,一種是非static方法,這兩種方法間的訪問將受到限制。
(1) static方法不能直接調用非static的方法或屬性;
(2)非static方法可以調用static的屬性或方法,不受限制。
可是為什麼會有這樣的限制呢。
使用static定義的屬性和方法,可以在沒有執行個體化對象的時候使用;而非static定義的屬性和方法,必須執行個體化對象之後才可以進行調用。
那麼,我們時候使用static方法。什麼時候使用static方法呢。
如果一個類中沒有任何屬性,只有方法,建議可以將所有的方法定義為static方法,這樣每次調用方法的時候就可以不進行對象執行個體化了。在實際開發中,建議優先考慮非static方法和非static屬性。
四、Java 主方法
Java方法定義時,如果一個方法在主類之中定義,並且由主方法直接調用的時候,那麼前面必須有public static,格式如下:
public static 傳回值類型 方法名稱 (參數列表) { [return [傳回值] ;]}
觀察以下代碼:
package com.wz.thisdemo;public class TestDemo { public static void main(String args[]) { print() ; // 直接調用 } public static void print() { System.out.println("Hello World .") ; }}
運行結果:
Hello World .
此時,表示的是一個static方法調用其他的static方法,但是如果這個print()方法上沒有static呢。
package com.wz.thisdemo;public class TestDemo { public static void main(String args[]) { print() ; // 直接調用 } public void print() { System.out.println("Hello World .") ; }}
運行結果:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: Cannot make a static reference to the non-static method print() from the type TestDemo at com.wz.thisdemo.TestDemo.main(TestDemo.java:5)
所有的非static方法幾乎都有一個特點:方法要由執行個體化對象調用。正確寫法如下:
package com.wz.thisdemo;public class TestDemo { public static void main(String args[]) { new TestDemo().print() ; // 對象調用 } public void print() { // 非static方法 System.out.println("Hello World .") ; }}
運行結果:
Hello World .
現在,來觀察主方法的組成:
public static void main(String args[]) {...}
可以發現裡面有很多的關鍵字:
(1)public:是一種存取權限,表示公用;
(2)static:此方法由類名稱直接調用;
(3)void:主方法是程式執行的開始;
(4)main:系統規定的一個方法名稱,執行類的時候預設找到此名稱,不能修改;
(5)String args[]:表示程式運行時傳遞的參數,通過字串接收。
五、static使用執行個體
統計一個類產生的執行個體化對象個數
分析: 一個類肯定可以有多個執行個體化對象產生,增加一個統計操作,可以統計出一個類之中的所產生的執行個體化對象的個數。如果現在要產生新的執行個體化對象,則一定會調用類中的構造方法,所以可以在構造方法中增加統計,而且這個統計的變數是所有對象共用的,應該將其定義為static屬性。
package com.wz.thisdemo;class Obj{ private static int count = 0; public Obj(){ System.out.println("count = " + ++count); }}public class TestDemo { public static void main(String args[]) { new Obj(); new Obj(); new Obj(); new Obj(); new Obj(); }}
運行結果:
count = 1count = 2count = 3count = 4count = 5