static關(guān)鍵字的用途
方便在沒有創(chuàng)建對象的情況下來進(jìn)行調(diào)用(方法/變量)。
被static關(guān)鍵字修飾的方法或者變量不需要依賴于對象來進(jìn)行訪問,只要類被加載了,就可以通過類名去進(jìn)行訪問。
static可以用來修飾類的成員方法、類的成員變量、內(nèi)部類,另外可以編寫static代碼塊來優(yōu)化程序性能。
static定義的資源(變量、靜態(tài)代碼塊)的初始化順序按照定義的順序進(jìn)行初始化。
static關(guān)鍵字的用法
(1)static靜態(tài)變量
被static修飾的變量屬于類變量,可以通過類名.變量名直接引用,而不需要new出一個對象來.static成員變量的初始化順序按照定義的順序進(jìn)行初始化。
靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有的對象所共享,在內(nèi)存中只有一份,它當(dāng)且僅當(dāng)在類初次加載時會被初始化。而非靜態(tài)變量是對象所擁有的,在創(chuàng)建對象的時候被初始化,各個對象擁有各自的變量互不影響。
另外記?。?strong>static是不允許用來修飾局部變量。比如

上面會報錯的,這是一個java的規(guī)范。
(2)static靜態(tài)方法
被static修飾的方法屬于類方法,可以通過類名.方法名直接引用,而不需要new出一個對象來,被static修飾的變量、被static修飾的方法統(tǒng)一屬于類的靜態(tài)資源,是類實例之間共享的,換言之,一處變、處處變。
在靜態(tài)方法中不能訪問非靜態(tài)成員方法和非靜態(tài)成員變量,但是在非靜態(tài)成員方法中是可以訪問靜態(tài)成員方法/變量的。舉個簡單的例子:

在上面的代碼中,由于print2方法是獨立于對象存在的,可以直接用過類名調(diào)用。假如說可以在靜態(tài)方法中訪問非靜態(tài)方法/變量的話,那么如果在main方法中有下面一條語句:
MyObject.print2();
此時對象都沒有,str2根本就不存在,所以就會產(chǎn)生矛盾了。同樣對于方法也是一樣,由于你無法預(yù)知在print1方法中是否訪問了非靜態(tài)成員變量,所以也禁止在靜態(tài)成員方法中訪問非靜態(tài)成員方法。而對于非靜態(tài)成員方法,它訪問靜態(tài)成員方法/變量顯然是毫無限制的。
這里總結(jié)一下靜態(tài)和非靜態(tài)之間的引用:
1、靜態(tài)方法能不能引用非靜態(tài)資源?不能,new的時候才會產(chǎn)生的東西,對于初始化后就存在的靜態(tài)資源來說,根本不認(rèn)識它。
2、靜態(tài)方法里面能不能引用靜態(tài)資源?可以,因為都是類初始化的時候加載的,大家相互都認(rèn)識。
3、非靜態(tài)方法里面能不能引用靜態(tài)資源?可以,非靜態(tài)方法就是實例方法,那是new之后才產(chǎn)生的,那么屬于類的內(nèi)容它都認(rèn)識。
(3)static靜態(tài)代碼塊
static關(guān)鍵字還有一個比較關(guān)鍵的作用就是 用來形成靜態(tài)代碼塊以優(yōu)化程序性能。static塊可以置于類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執(zhí)行每個static塊,并且只會執(zhí)行一次。
為什么說static塊可以用來優(yōu)化程序性能,是因為它的特性:只會在類加載的時候執(zhí)行一次
(4)static靜態(tài)內(nèi)部類
static一般情況下來說是不可以修飾類的,如果static要修飾一個類,說明這個類是一個靜態(tài)內(nèi)部類(注意static只能修飾一個內(nèi)部類)
static關(guān)鍵字的誤區(qū)
- (1) 能通過this訪問靜態(tài)成員變量嗎?
雖然對于靜態(tài)方法來說沒有this,那么在非靜態(tài)方法中能夠通過this訪問靜態(tài)成員變量嗎?先看下面的一個例子,這段代碼輸出的結(jié)果是什么?
public class Main {
static int value = 33;
public static void main(String[] args) throws Exception{
new Main().printValue();
}
private void printValue(){
int value = 3;
System.out.println(this.value);
}
}
輸出結(jié)果:
33
這里面主要考察隊this和static的理解。this代表什么?this代表當(dāng)前對象,那么通過new Main()來調(diào)用printValue的話,當(dāng)前對象就是通過new Main()生成的對象。而static變量是被對象所享有的,因此在printValue中的this.value的值毫無疑問是33。在printValue方法內(nèi)部的value是局部變量,根本不可能與this關(guān)聯(lián),所以輸出結(jié)果是33。在這里永遠(yuǎn)要記住一點:靜態(tài)成員變量雖然獨立于對象,但是不代表不可以通過對象去訪問,所有的靜態(tài)方法和靜態(tài)變量都可以通過對象訪問(只要訪問權(quán)限足夠)。
- (2) static能作用于局部變量么?
在C/C++中static是可以作用域局部變量的,但是在Java中切記:static是不允許用來修飾局部變量。不要問為什么,這是Java語法的規(guī)定。
常見的筆試面試題
1.下面這段代碼的輸出結(jié)果是什么?
public class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
輸出結(jié)果
base static
test static
base constructor
test constructor
至于為什么是這個結(jié)果,我們先不討論,先來想一下這段代碼具體的執(zhí)行過程,在執(zhí)行開始,先要尋找到main方法,因為main方法是程序的入口,但是在執(zhí)行main方法之前,必須先加載Test類,而在加載Test類的時候發(fā)現(xiàn)Test類繼承自Base類,因此會轉(zhuǎn)去先加載Base類,在加載Base類的時候,發(fā)現(xiàn)有static塊,便執(zhí)行了static塊。在Base類加載完成之后,便繼續(xù)加載Test類,然后發(fā)現(xiàn)Test類中也有static塊,便執(zhí)行static塊。在加載完所需的類之后,便開始執(zhí)行main方法。在main方法中執(zhí)行new Test()的時候會先調(diào)用父類的構(gòu)造器,然后再調(diào)用自身的構(gòu)造器。因此,便出現(xiàn)了上面的輸出結(jié)果。
2.這段代碼的輸出結(jié)果是什么?
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
輸出結(jié)果:
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
類似地,我們還是來想一下這段代碼的具體執(zhí)行過程。首先加載Test類,因此會執(zhí)行Test類中的static塊。接著執(zhí)行new MyClass(),而MyClass類還沒有被加載,因此需要加載MyClass類。在加載MyClass類的時候,發(fā)現(xiàn)MyClass類繼承自Test類,但是由于Test類已經(jīng)被加載了,所以只需要加載MyClass類,那么就會執(zhí)行MyClass類的中的static塊。在加載完之后,就通過構(gòu)造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,因此會執(zhí)行Test中的Person person = new Person(),而Person類還沒有被加載過,因此會先加載Person類并執(zhí)行Person類中的static塊,接著執(zhí)行父類的構(gòu)造器,完成了父類的初始化,然后就來初始化自身了,因此會接著執(zhí)行MyClass中的Person person = new Person(),最后執(zhí)行MyClass的構(gòu)造器。
3.這段代碼的輸出結(jié)果是什么?
public class Test {
static{
System.out.println("test static 1");
}
public static void main(String[] args) {
}
static{
System.out.println("test static 2");
}
}
輸出結(jié)果:
test static 1
test static 2
static塊可以出現(xiàn)類中的任何地方(只要不是方法內(nèi)部,記住,任何方法內(nèi)部都不行),并且執(zhí)行是按照static塊的順序執(zhí)行的。