Java 中被static 修飾的域或方法常被稱作靜態的,那么什么叫做靜態的呢?下面我們就來了解一下Java中的靜態域與靜態方法。
1、靜態域
如果將靜態域定義為static ,那么每個類中只有一個這樣的域,而每一個對象對於所有的實例域都有自己的一份拷貝本。例如,學生類中有一個實例域studentId和一個靜態域nextId, 如下所示:
那么,每一個學生對象,都會有自己的studentId, 但是這個類的所以對象將共享一個nextId域, 換句話說就是: 如果有100個Student類對象 ,那么有100個實例域studentId,每一個student都有自己的一份,但是只有一個靜態域nextId , 100個學生對象共享這一個靜態域nextId, 使沒有學生對象,靜態域也是存在的,它是屬於類的,而不是屬於任何獨立的對象。靜態域(靜態方法)可以直接用類名來調用,而不用創建對象用對象來調用(在絕大多數的面向對象的語言中,靜態域被稱作為類域。術語“static” 只是沿用了C++的叫法,並無實際意義)。
下面在Student類中實現一個setId() 方法:
public void setId(){ studentId = nextId + ""; nextId++; }
假定為student1 對象設置studnetId 即: student1.setId(); 那么studnet1的實例域studentId 被設置為靜態域nextId當前的值,並且靜態域nextId 的值進行了自增運算。這個的作用相當於:
student1.id = Student.nextId;
Student.nextId++;
2、靜態常量
靜態變量使用的比較少,但是靜態常量卻使用的比較多(在實際的開發中,靜態常量可以做到:該改一處而改全處作用,大大的減少修改和出錯的地方),例如在Java中的Math類中定義了一個圓周率的靜態常量:
在使用的時候,我們就可以跟使用靜態變量、靜態方法方法一樣使用靜態常量(用靜態static修飾的都是可以直接用類名來使用) Math.PI來使用這個常量。
如果關鍵字static被省略,那么PI就變成Math類的一個實例域,需要通過Math類的對象訪問PI,並且每一個Math對象都有它自己的一個PI復制本。
另外一個多次使用的靜態常量是Java中System.out. 它在System類中聲明:
- public class System{
- ...
- public static final PrintStream = ...;
- ...
- }
我們都知道每個類對象都可以對公有域進行修改,所以,最好不要將域設計成為public ,然而,公有常量(即final域)卻沒有問題,因為out被聲明為final, 所以,不允許再將其他的打印流賦值給它:
System.out = new PrintStream(...); //這是做法是錯誤的
注意: 查看System類,就會發現有一個setOut方法,它可以將System.out.設置為不同的流,那么我們可能會感到奇怪,為什么這個方法可以修改final 變量的值,原因在於,setOut方法是一個本地方法,而不是用Java語言實現的(用的是C語言實現),本地方法可以繞過Java語言的存取控制機制,這是一種特殊的方法,在編寫程序的時候,我們不應該這樣處理,但是在android開發中有些開發是要寫本地方法,然后用C語言實現,再再Java環境中調用C語言,這里就不做過多的講解了。
3、靜態方法
靜態方法是一種不能由對象操作的方法, 例如Math類中的求取一個數的次方的pow()方法就是一個靜態方法。表達式是: Math.pow(x, a),在運算時,不使用任何Math對象,換句話說,沒有隱式的參數。可以認為靜態方法是沒有this參數的方法(在一個非靜態的方法中,this參數表示這個方法的隱式參數)。
Student 類的靜態方法不能訪問Id實例域,因為Id它不是靜態的,Student的靜態方法它不能操作對象,但是靜態方法可以訪問自身類中的靜態域。總之就是常說的:靜態方法中只能調用靜態的東西,非靜態的是不能使用的。
- public static int getNextId{
- return nextId; // 返回靜態域
- }
這個方法通過類名Student.getNextId()來調用,那么這個方法可以省略關鍵字static嗎? 回答是肯定的,但是需要通過Student類的對象來調用這個方法了。
在下面兩種情況下使用靜態方法:
1、一個方法不需要訪問對象狀態,其所需參數都是通過顯示參數提供(例如: Math.pow()).
2、一個方法只需要訪問類的靜態域(例如:Student.getNextId() ).
4、工廠方法
靜態方法還有一種常見的用途,例如:NumberFormat類使用工廠方法產生不同風格的格式對象:
-
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); doublen n = 0.3; System.out.println(currencyFormatter.format(n)); // 輸出 ¥0.30 System.out.println(percentFormatter.format(n)); //輸出 30%
為什么NumberFormat類不利用構造器完成這些操作呢?主要的原因有兩個:
1、無法命名構造器。構造器的名字必須與類名相同,但是,這里希望將得到的貨幣實例和百分比實例采用不同的名字。
2、當使用構造器時,無法改變所構造的對象類型。而Factory方法將返回一個DecimalFormat類對象,這是NumberFormat的子類。
5、main方法
我們學習java的時候,程序中大多會有一個main 方法,我們都稱作程序的入口,main方法不對任何對象進行操作,事實上,在啟動程序的時候,還沒有任何一個對象,靜態的main方法將執行並創建程序所需的對象。
