final定義的變數可以看做一個常量,不能被改變;
final定義的方法不能被覆蓋;
final定義的類不能被繼承。
final static 就是再加上static的特性就可以了
static 和final是沒有直接關係的
static 是在記憶體中分配一塊地區,供整個類通用,所有的類的對象都享有它的共同的值
static 和final的區別
一、static :
什麼情況下我們要使用static呢?
1、只想用一個儲存地區來儲存一個特定的資料——無論要建立多少個對象,甚至根本不創 建對象。
2、我們需要一個特殊的方法,它沒有與這個類的任何對象關聯。也就是說,即使沒有建立對象,也需要一個能調用的方法。
為滿足這兩方面的要求,可使用static(靜態)關鍵字。
下面我先舉個例子:
一旦將什麼東西設為static,資料或方法就不會同那個類的任何對象執行個體聯絡到一起。所以儘管從未建立那個類的一個對象,仍能調用一個static方法,或訪問一些static資料。
為了將資料成員或方法設為static,只需在定義前置和這個關鍵字即可。
例如,下述代碼能產生一個static資料成員,並對其初始化:
class StaticTest {
Static int i = 47;
}
現在,儘管我們製作了兩個StaticTest對象,但它們仍然只佔據StaticTest.i的一個儲存空間。這兩個對象都共用同樣的i。請考察下述代碼:
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
此時,無論st1.i還是st2.i都有同樣的值47,因為它們引用的是同樣的記憶體地區。
有兩個辦法可引用一個static變數。正如上面展示的那樣,可通過一個對象命名它,如st2.i。亦可直接用它的類名引用,而這在非靜態成員裡是行不通的(最好用這個辦法引用static變數,因為它強調了那個變數的“靜態”本質)。
StaticTest.i++;
其中,++運算子會使變數增值。此時,無論st1.i還是st2.i的值都是48。
類似的邏輯也適用於靜態方法。既可象對其他任何方法那樣通過一個對象引用靜態方法,亦可用特殊的文法格式“類名.方法()”加以引用。靜態方法的定義是類似的:
class StaticFun {
static void incr() { StaticTest.i++; }
}
從中可看出,StaticFun的方法incr()使待用資料i增值。可用典型的方法調用incr():
StaticFun sf = new StaticFun();
sf.incr();
或者,由於incr()是一種靜態方法,所以可通過它的類直接調用:
StaticFun.incr();
對方法來說,static一項重要的用途就是協助我們在不必建立對象的前提下調用那個方法。
舉簡單一例如下:
public class TestStatic {<br />public static void main(String args[]){<br />PhoneCard mycard_1 = new PhoneCard();//建立第一張卡對象<br />PhoneCard mycard_2 = new PhoneCard();//建立第二張卡對象<br />mycard_1.addFee = 0.8;//給第一張卡的附加費addFee賦值為0.8<br />//注意到我們沒有給第二張卡賦值<br />System.out.println("第一張卡的附加費:" + mycard_1.addFee);<br />System.out.println("第二張卡的附加費:" + mycard_2.addFee);<br />//發現沒有?輸出結果中第二張卡的附加費也是0.8 了。<br />System.out.println("卡的附加費:" + PhoneCard.addFee);<br />//該句的列印輸出表明卡類的附加費都是0.8<br />}<br />}<br />class PhoneCard{<br />static double addFee;//靜態域addFee<br />}<br />
該例建立了兩個類,PhoneCard類只定義了一個變數,TestStatic類裡建立了兩個PhoneCard類對象,並給其中的一個對象的附加費addFee賦值,而另一個對象沒賦值。
由上例可以看出,靜態域儲存在類的公用儲存單元,而不是儲存在對象的儲存單元內。
static 修飾方法時是同理。
二、final:
final可修飾類、域(變數和常量)、方法 (而static不修飾類)
1、final修飾類,表示該類不可被繼承。
如定義了一個final類:
final class SnowBird{<br />int i;<br />String s;<br />static void fly(){<br />System.out.println("snowbird is flying");<br />}<br />}<br />//現在定義一個類,試圖繼承SnowBird類:<br />public class Bird extends SnowBird{<br />public static void main(String[] args){<br />SnowBird.fly();<br />}<br />}<br />
把上面的兩個類拷貝到檔案中,檔案名稱儲存為Bird.java ,現在編譯看看會出現什麼問題?
出錯資訊是:cannot inherit from final SnowBird
表明final 類不可被繼承。
那麼,final修飾變數是怎麼樣呢?
2、final修飾變數
程式中經常需要定義各種類型的常量,如:3.24268,"201"等等。這時候我們就用final來修飾一個類似於標誌符名字。如:
final String connectNumber = "201";
final表明 connectNumber是一個常量,它的取值在整個過程都不會改變。
如果把final 去掉則connectNumber就成為變數了。
有時我們為了節省空間的,常量通常聲明為 static .因為如上所說的 static 用的是類的記憶體空間。
3、修飾方法:
final修飾的方法,稱為最終方法。最終方法不可被子類重新定義,即不可被覆蓋。
如父類定義了public void fly(){ ....}
則子類就不能定義
public void fly(){。。。。。。}
但注意覆蓋與重載的區別。不能被覆蓋並不是不能被重載,如你還可以定義
public void fly(int i){.....},
舉個例子如下:
class FinalValue {<br />static final int i = 1;<br />final void fly(){<br />System.out.println("SnowBird is flying over FinalValue ");<br />}<br />}<br />class TestFinal extends FinalValue {<br />int i = 2;<br />void fly(){<br />System.out.println("SnowBird is flying over TestFinal");<br />System.out.println("In class FinalValue static Final i = "+ FinalValue.i);<br />System.out.println("In class TestFinal i = "+ i);<br />}<br />void fly(String s){<br />System.out.println("fly("+ s + ")");<br />}<br />}<br />public class Test {<br />public static void main(String args[]){<br />TestFinal tf = new TestFinal();<br />tf.fly();<br />tf.fly("ok");<br />System.out.println(tf.i);<br />}<br />}
把上面的程式儲存為Test.java編譯看看,出現什麼錯誤?
然後,把TestFinal類中的 void fly(){ ... } 註解掉
即 如下
/* void fly(){<br />System.out.println("SnowBird is flying over TestFinal");<br />System.out.println("In class FinalValue static Final i = "+ FinalValue.i);<br />System.out.println("In class TestFinal i = "+ i);<br />}*/
現在再編譯看看通過了嗎? 可見重載與覆蓋的區別了吧。 還發現 FinalValue中的 i 與 TestFinal中的 i 沒關係 。因為對於變數而言,重定義只是父類的同名域被隱藏了而已。