1、Static
static表示「全局」或者「靜態」的意思
用來修飾成員變量和成員方法,也能夠造成靜態static代碼塊。
1.非static數據和方法
類中普通聲明的數據和方法都是非static的,即不加static進行修飾,對於這類數據和方法咱們在使用的時候都是隻能經過建立對象實例後,經過實例進行調用。
public class StaticTest {
public int i=0;
public StaticTest() {
super();
// TODO Auto-generated constructor stub
}
public StaticTest(int i) {
super();
this.i = i;
}
public void sayHello() {
System.out.println("hello");
}
public static void main(String[] args) {
StaticTest test = new StaticTest(4);
int a= test.i; //訪問數據域
test.sayHello(); //調用方法
}
}
2.Static修飾的數據和方法
被static修飾的成員變量和成員方法獨立於該類的任何對象,也就是說,它不依賴類特定的實例,被類的全部實例共享。只要這個類被加載,Java虛擬機就能根據類名在運行時數據區的方法區內定找到他們。所以,static對象能夠在它的任何對象建立以前訪問,無需引用任何對象。
public class StaticTest {
public static int i =1;
public static void sayHello() {
System.out.println("hello");
}
public static void main(String[] args) {
int a = StaticTest.i; //直接經過類名調用,不須要建立響應的實例對象
StaticTest.sayHello();
}
}
因此被static 修飾的數據和方法也叫做類數據和類方法。
1)、static變量
按照是否靜態的對類成員變量進行分類可分兩種:一種是被static修飾的變量,叫靜態變量或類變量;另外一種是沒有被static修飾的變量,叫實例變量。二者的區別是:
對於靜態變量在內存中只有一個拷貝(節省內存),JVM只爲靜態分配一次內存,在加載類的過程當中完成靜態變量的內存分配,可用類名直接訪問(方便),固然也能夠經過對象來訪問(可是這是不推薦的)。
對於實例變量,沒建立一個實例,就會爲實例變量分配一次內存,實例變量能夠在內存中有多個拷貝,互不影響(靈活)。
2)、靜態方法
靜態方法能夠直接經過類名調用,任何的實例也均可以調用,所以靜態方法中不能用this和super關鍵字,不能直接訪問所屬類的實例變量和實例方法(就是不帶static的成員變量和成員成員方法),只能訪問所屬類的靜態成員變量和成員方法。
由於static方法獨立於任何實例,所以static方法必須被實現,而不能是抽象的abstract。
public class StaticTest {
public static int i =1;
public int j =2;
public StaticTest(int j) {
super();
this.j = j;
i++; //沒建立一個實例,i++
}
public static void sayHello() {
System.out.println("hello i= "+i);
//System.out.println(j); // 靜態方法裏面不能使用非靜態變量
}
public int getJ() {
return this.j;
}
public void changeJ(int a) {
this.j=a;
}
public static void main(String[] args) {
StaticTest.sayHello();
StaticTest test1 = new StaticTest(9);
StaticTest.sayHello();
System.out.println("test1.J = "+test1.getJ());
StaticTest test2 = new StaticTest(8);
StaticTest.sayHello();
System.out.println("test2.J = "+test2.getJ());
System.out.println("test1.J = "+test1.getJ());
test1.changeJ(100);//非靜態變量依賴於實例,而且每一個實例之間的非靜態變量之間相互獨立
System.out.println("test1.J = "+test1.getJ());
System.out.println("test2.J = "+test2.getJ());
//同一個類,擁有共同的靜態變量
StaticTest.i++;
StaticTest.sayHello();
System.out.println(test1.i);
System.out.println(test2.i);
}
}
結果:
hello i= 1
hello i= 2
test1.J = 9
hello i= 3
test2.J = 8
test1.J = 9
test1.J = 100
test2.J = 8
hello i= 4
4
4
3)、static代碼塊
static代碼塊也叫靜態代碼塊,是在類中獨立於類成員的static語句塊,能夠有多個,位置能夠隨便放,它不在任何的方法體內,JVM加載類時會執行這些靜態的代碼塊,若是static代碼塊有多個,JVM將按照它們在類中出現的前後順序依次執行它們,每一個代碼塊只會被執行一次
public class StaticTest {
public static int a ;
public static int b;
public static int c;
static {
a=1;
b=2;
System.out.println(StaticTest.a);
System.out.println(StaticTest.b);
}
public StaticTest() {
super();
System.out.println("Constructor...");
}
public static void main(String[] args) {
System.out.println("main method");
StaticTest staticTest = new StaticTest();
}
static {
c=3;
System.out.println(StaticTest.c);
}
}
結果:
1
2
3
main method
Constructor...
利用靜態代碼塊能夠對一些static變量進行賦值,最後再看一眼這些例子,能夠看到靜態變量,靜態代碼塊都是在main方法以前被執行,即靜態變量即代碼塊都是在類加載的時候就已經執行完成。
2、final
根據程序上下文環境,Java關鍵字final有「這是沒法改變的」或者「終態的」含義,它能夠修飾非抽象類、非抽象類成員方法和變量。你可能出於兩種理解而須要阻止改變:設計或效率。
[] final類不能被繼承,沒有子類,final類中的方法默認是final的。
[] final方法不能被子類的方法覆蓋,但能夠被繼承。
[] final成員變量表示常量,只能被賦值一次,賦值後值再也不改變。
[] final不能用於修飾構造方法。
[] 注意:父類的private成員方法是不能被子類方法覆蓋的,所以private類型的方法默認是final類型的。
1)final變量(常量)
用final修飾的成員變量表示常量,值一旦給定就沒法改變!
final修飾的變量有三種:靜態變量、實例變量和局部變量,分別表示三種類型的常量。
從下面的例子中能夠看出,一旦給final變量初值後,值就不能再改變了。
另外,final變量定義的時候,能夠先聲明,而不給初值,這中變量也稱爲final空白,不管什麼狀況,編譯器都確保空白final在使用以前必須被初始化。可是,final空白在final關鍵字final的使用上提供了更大的靈活性,爲此,一個類中的final數據成員就能夠實現依對象而有所不一樣,卻有保持其恆定不變的特徵。
public class FinalTest {
private final String S = "final實例變量S";
private final int A = 100;
public final int B = 90;
public static final int C = 80;
private static final int D = 70;
public final int E; //final空白,必須在初始化對象的時候賦初值
public FinalTest(int x) {
E = x;
}
/**
* @param args
*/
public static void main(String[] args) {
FinalTest t = new FinalTest(2);
//t.A=101; //出錯,final變量的值一旦給定就沒法改變
//t.B=91; //出錯,final變量的值一旦給定就沒法改變
//t.C=81; //出錯,final變量的值一旦給定就沒法改變
//t.D=71; //出錯,final變量的值一旦給定就沒法改變
System.out.println(t.A);
System.out.println(t.B);
System.out.println(t.C); //不推薦用對象方式訪問靜態字段
System.out.println(t.D); //不推薦用對象方式訪問靜態字段
System.out.println(FinalTest.C);
System.out.println(FinalTest.D);
//System.out.println(Test3.E); //出錯,由於E爲final空白,依據不一樣對象值有所不一樣.
System.out.println(t.E);
FinalTest t1 = new FinalTest(3);
System.out.println(t1.E); //final空白變量E依據對象的不一樣而不一樣
}
private void test() {
System.out.println(new FinalTest(1).A);
System.out.println(FinalTest.C);
System.out.println(FinalTest.D);
}
public void test2() {
final int a; //final空白,在須要的時候才賦值
final int b = 4; //局部常量--final用於局部變量的情形
final int c; //final空白,一直沒有給賦值.
a = 3;
//a=4; 出錯,已經給賦過值了.
//b=2; 出錯,已經給賦過值了.
}
}
2)、final參數
當函數參數爲final類型時,你能夠讀取使用該參數,可是沒法改變該參數的值。
public void f1(final int i) {
//i++; //i是final類型的,值不容許改變的.
System.out.print(i);
}
3)final方法
若是一個類不容許其子類覆蓋某個方法,則能夠把這個方法聲明爲final方法。
使用final方法的緣由有二:
第1、把方法鎖定,防止任何繼承類修改它的意義和實現。
第2、高效。編譯器在遇到調用final方法時候會轉入內嵌機制,大大提升執行效率。
private類型的方法默認是final類型的。
4)final類
final類不能被繼承,所以final類的成員方法沒有機會被覆蓋,默認都是final的。在設計類時候,若是這個類不須要有子類,類的實現細節不容許改變,而且確信這個類不會載被擴展,那麼就設計爲final類。
例如:Java中String就是一個最最多見的final類。
思考問題:Java中爲何將String定義爲final類?
將方法或類聲明爲final主要目的是:確保它們不會再子類中改變語義。String類是final類,這意味着不容許任何人定義String的子類。換言之,若是有一個String的引用,它引用的必定是一個String對象,而不多是其餘類的對象。
——《Java核心技術 卷I》
String是應用類型,而Java中String是最經常使用的一個類,如同一個基本數據類型同樣常見,將其定義成final類型的一是由於String使用頻率過高,定義成final可以如基本數據類型同樣方便使用,二是出於安全性問題,定義爲final,可以保證String在使用中值不變,更加安全。
示例1
package _12_01字符串;
public class 爲何String要設計成不可變類你 {
public static void main(String[] args) {
String a, b, c;
a = "test";
b = a;
c = b;
String processA = processA(a);
String processB = processB(b);
String processC = processC(c);
System.out.println(processA);
System.out.println(processB);
System.out.println(processC);
}
static String processA(String str){
return str + "A";
}
static String processB(String str){
return str + "B";
}
static String processC(String str){
return str + "C";
}
}
//OUTPUT
// testA
//testB
//testC
當String支持非可變性的時候,它們的值很好肯定,無論調用哪一個方法,都互不影響。
若是String是可變的,就可能以下例,咱們使用StringBuffer來模擬String是可變的
package _12_01字符串;
public class 爲何String要設計成不可變類2 {
public static void main(String[] args) {
StringBuffer a, b, c;
a = new StringBuffer("test");
b = a;
c = b;
String processA = processA(a);
String processB = processB(b);
String processC = processC(c);
System.out.println(processA);
System.out.println(processB);
System.out.println(processC);
}
static String processA(StringBuffer str){
return str.append("A").toString();
}
static String processB(StringBuffer str){
return str.append("B").toString();
}
static String processC(StringBuffer str){
return str.append("C").toString();
}
}
//OUTPUT
// testA
//testAB
//testABC
能看出b=a,c=b;程序員的本意是但願變量是不變的。因此String不可變的安全性就體如今這裏。實際上StringBuffer的做用就是起到了String的可變配套類角色。