7--黑馬程式設計師--技術總結之幾個重要的關鍵字
、期待與您交流! ----------------------
一.static關鍵字
static表示“全域性”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static程式碼塊,但是Java語言中沒有全域性變數的概念。
被static修飾的成員變數和成員方法獨立於該類的任何物件。也就是說,它不依賴類特定的例項,被類的所有例項共享。
只要這個類被載入,Java虛擬機器就能根據類名在執行時資料區的方法區內定找到他們。因此,static物件可以在它的任何物件建立之前訪問,無需引用任何物件。
用public修飾的static成員變數和成員方法本質是全域性變數和全域性方法,當宣告它類的物件市,不生成static變數的副本,而是類的所有例項共享同一個static變數。
static變數前可以有private修飾,表示這個變數可以在類的靜態程式碼塊中,或者類的其他靜態成員方法中使用(當然也可以在非靜態成員方法中使用),但是不能在其他類中通過類名來直接引用,這一點很重要。實際上你需要搞明白,private是訪問許可權限定,static表示不要例項化就可以使用,這樣就容易理解多了。static前面加上其它訪問許可權關鍵字的效果也以此類推。
static修飾的成員變數和成員方法習慣上稱為靜態變數和靜態方法,可以直接通過類名來訪問,訪問語法為:
類名.靜態方法名(引數列表...)
類名.靜態變數名
用static修飾的程式碼塊表示靜態程式碼塊,當Java虛擬機器載入類時,就會執行該程式碼塊。
1、static變數(靜態變數)和例項變數
按照是否靜態的對類成員變數進行分類可分兩種:一種是被static修飾的變數,叫靜態變數或類變數;另一種是沒有被static修飾的變數,叫例項變數。
兩者的區別是:
對於靜態變數在記憶體中只有一個拷貝(節省記憶體),JVM只為靜態分配一次記憶體,在載入類的過程中完成靜態變數的記憶體分配,可用類名直接訪問(方便),當然也可以通過物件來訪問(但是這是不推薦的,會浪費記憶體)。
對於例項變數,沒建立一個例項,就會為例項變數分配一次記憶體,例項變數可以在記憶體中有多個拷貝,互不影響(靈活)。
所以一般在需要實現以下兩個功能時使用靜態變數:
1)在物件之間共享值時,即當類中的成員需要被所有物件共享時,用static修飾
2)方便訪問變數時
程式碼示例:
- public class StaticDemo1 {
- /**分別通過類和物件來讀取靜態變數
- * @黑馬ZWF
- */
- public static void main(String[] args) {
- 梯形 t = new 梯形(3.0f, 10.0f, 20);
- 梯形.下底 = 200; //通過類操作靜態變數
- System.out.println("梯形的下底為" + t.獲取下底() );
- t.修改下底(100); //通過物件操作靜態變數
-
System.out.println("梯形的下底為" + t.獲取下底() );
- }
- }
- class 梯形 {
- float 上底, 高;
- static float 下底;
- 梯形(float x, float y, float h) {
- 上底 = x;
- 下底 = y;
- 高 = h;
- }
- float 獲取下底 () {
- return 下底;
- }
- static void 修改下底(float b) {
- 下底 = b;
- }
- }
2.靜態方法
類體中的方法分為例項方法和類方法兩種,用static修飾的是類方法。當一個類建立了一個物件後,這個物件就可以呼叫該類的方法。那麼例項方法和類方法有什麼區別呢?
當類的位元組碼檔案被載入到記憶體時,類的例項方法不會被分配入口地址,當該類建立物件後,類中的例項方法才分配入口地址,從而例項方法可以被類建立的任何物件呼叫執行。需要注意的是,當建立第一個物件時,類中的例項方法就分配了入口地址,當再建立物件時,不再分配入口地址,也就是說,方法的入口地址被所有的物件共享,當所有的物件都不存在時,方法的入口地址才被取消。例項方法必須通過物件來呼叫,當某個物件呼叫例項方法時,該例項方法中出現的成員變數被認為是分配給該物件的成員變數,其中的類變數和其他物件共享,所以,例項方法既可以操作例項變數也可以操作類變數。
對於類中的類方法,在該類被載入到記憶體時,就分配了相應的入口地址。從而類方法不僅可以被類建立的任何物件呼叫執行,也可以直接通過類名呼叫。類方法的入口地址直到程式退出才被取消。所以Java規定:類方法中出現的成員變數必須是被所有物件共享的變數(類變數),即類方法不可以操作例項變數,這樣規定的原因是:在類建立物件之前,例項成員變數還沒有分配記憶體。類方法也不可以呼叫其他的例項方法,這是因為在類建立物件之前,例項方法也沒有入口地址。
無論是類方法或例項方法,當被呼叫執行時,方法中的區域性變數才被分配記憶體空間,方法呼叫完畢,區域性變數即刻釋放所佔的肉存。在一個方法被呼叫執行完畢之前,如果該方法又被呼叫,那麼,方法的區域性變數會再次被分配新的記憶體空間,比如,方法在遞迴呼叫時,方法中的區域性變數會再次被分配新的記憶體空間。在下面的程式碼示例中,我將通過遞迴呼叫類中的方法,計算出Fibinacii序列的第8項(Fibinacii序列的前兩項是1,後續每項的值都是該項的前兩項之和)
- public class StaticDemo2 {
- /**通過遞迴呼叫類中的方法,計算出Fibinacii序列的第8項
- * @黑馬ZWF
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- System.out.println("Fibinacii的第八項是" + Fibinacii.fibinacii(8)); //輸出結果是21
- }
- }
- class Fibinacii {
- public static int fibinacii(int n) {
- if (n == 1||n ==2) //Fibinacii的前兩項都是1
- return 1;
- else
- return fibinacii(n - 1) + fibinacii(n - 2); //通過自身的遞迴呼叫fibinacii方法得出結果
- }
- }
二.this關鍵字
例項方法可以操作類的成員變數,當例項成員變數在例項方法中出現時,預設的格式為:
this.成員變數
當static成員變數在例項方法中出現時,預設的格式為:
類名.成員變數
如:
- public class ThisDemo {
- int x;
- static int y; //定義靜態變數y
- void f () {
- this.x=100; //this.成員變數
- ThisDemo.y=200; //類名.成員變數
- }
- }
在上述A類中的方法f中出現了this關鍵字,this代表使用方法f的當前物件。所以,this.x就表示當前物件的變數x,當物件呼叫方法f時,將100賦給該物件的變數x。因此,當一個物件呼叫方法時,方法中的例項成員變數就是指分配給該物件的例項成員變數,而static變數和其他物件共享。因此,通常情況下,可以省略例項成員變數名字前面的“this.”以及static變數前面的“類名.”。如:
- public class ThisDemo {
- int x;
- static int y; //定義靜態變數y
- void f () {
- x=100; //省略this關鍵字
- y=200; //省略類名
- }
- }
類的例項方法可以呼叫類的其他方法,對於例項方法呼叫的預設格式為:
this.方法;
對於類方法呼叫的預設格式為:
類名.方法;
如:
- public class ThisDemo2 {
- void f () {
- this.g(); //this.方法名
- ThisDemo2.h(); //類名.方法名
- }
- void g(){
- System.out.println("ok") ;
- }
- static void h() {
- System.out.println("hello") ;
- }
- }
在上述B類中的方法f中出現了this關鍵字,this代表使用方法f的當前物件。所以,方法f的方法體中this.g()就是當前物件呼叫方法g,也就是說,當某個物件呼叫方法f過程中,又呼叫了方法go由於這種邏輯關係非常明確,因此一個例項方法呼叫另一個方法時可以省略方法名字前面的“this.”或“類名.”。如:
- public class ThisDemo2 {
- void f () {
- g(); //省略this
- h(); //省略類名
- }
- void g(){
- System.out.println("ok") ;
- }
- static void h() {
- System.out.println("hello") ;
- }
- }
注:this關鍵字不能出現在類方法中,這是因為,類方法可以通過類名直接呼叫。
三.final關鍵字
final關鍵字可以修飾類、成員變數和方法巾的引數。
final類不能被繼承,即不能有子類。如:
final class A{
···
)
A就是一個final類。有時候是出於安全性的考慮,將一些類修飾為final類。例如:Java提供的String類,它對於編譯器和直譯器的正常執行有很重要的作用,對它不能輕易改變,
因此它被修飾為final類。
如果一個方法被修飾為final方法,則這個方法不能被重寫。
如果一個成員變數被修飾為final的,就是常量,常量必須賦給初值,而且不能再發生變化。
如果方法的引數被修飾為final的,該引數的值不能被改變。
在下面的程式碼示例中,A類中szetArea方法的引數r使用final修飾。這種邏輯關係非常明確,因此一個例項方法呼叫另一個方法時可以省略方法名字前面的“this.”或“類名.”。如:
- public class FinalDemo {
- public static void main(String[] args) {
- A a = new A();
- System.out.println("半徑為100的圓面積為:" + a.getArea(100));
- }
- }
- class A {
- //final double PI, //非法,因為沒有給初值
- final double PI=3.1415926;// PI是常量且給定初值
- public double getArea(final double r) {
- //r=89; 非法,因為r已經被final修飾,不允許再改變r的值
- return PI *r * r;
- }
- }