溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

static關(guān)鍵字作用是什么

發(fā)布時間:2020-07-21 10:44:43 來源:億速云 閱讀:210 作者:Leah 欄目:編程語言

這篇文章將為大家詳細(xì)講解有關(guān)static關(guān)鍵字作用是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

static關(guān)鍵字的含義及使用場景

static是Java50個關(guān)鍵字之一。static關(guān)鍵字可以用來修飾代碼塊表示靜態(tài)代碼塊,修飾成員變量表示全局靜態(tài)成員變量,修飾方法表示靜態(tài)方法。(注意:不能修飾普通類,除了內(nèi)部類,這是為什么?)

class A {
	static {
		System.out.println("A : 靜態(tài)代碼塊");
	}
	
	static int i ;  // 靜態(tài)變量
	
	static void method() {
		System.out.println("A: 靜態(tài)方法");
	}
}

簡而言之,被static關(guān)鍵字修飾的內(nèi)容都是靜態(tài)的。

靜態(tài)是相對于動態(tài)的,動態(tài)是指Java程序在JVM上運行時,JVM會根據(jù)程序的需要動態(tài)創(chuàng)建對象并存儲對象(分配內(nèi)存),對象使命結(jié)束后,對象會被垃圾回收器銷毀,即內(nèi)存回收由JVM統(tǒng)一管理并分配給其他新創(chuàng)建的對象;靜態(tài)是指Java程序還沒有運行時,JVM就會為加載的類分配空間存儲被static關(guān)鍵字修飾的內(nèi)容;如靜態(tài)成員變量,Java類加載到JVM中,JVM會把類以及類的靜態(tài)成員變量存儲在方法區(qū),我們知道方法區(qū)是線程共享且很少發(fā)生GC的區(qū)域,所以被static關(guān)鍵字修飾的內(nèi)容都是全局共享的,且只會為其分配一次存儲空間。

所以當(dāng)類的某些內(nèi)容不屬于對象,而由對象共享即屬于類的時候,就可以考慮是否用static關(guān)鍵字進(jìn)行修飾。

static關(guān)鍵字的的作用

1 修飾代碼塊

類中用static關(guān)鍵字修飾的代碼塊稱為靜態(tài)代碼,反之沒有用static關(guān)鍵字修飾的代碼塊稱為實例代碼塊。

實例代碼塊會隨著對象的創(chuàng)建而執(zhí)行,即每個對象都會有自己的實例代碼塊,表現(xiàn)出來就是實例代碼塊的運行結(jié)果會影響當(dāng)前對象的內(nèi)容,并隨著對象的銷毀而消失(內(nèi)存回收);而靜態(tài)代碼塊是當(dāng)Java類加載到JVM內(nèi)存中而執(zhí)行的代碼塊,由于類的加載在JVM運行期間只會發(fā)生一次,所以靜態(tài)代碼塊也只會執(zhí)行一次。

因為靜態(tài)代碼塊的主要作用是用來進(jìn)行一些復(fù)雜的初始化工作,所以靜態(tài)代碼塊跟隨類存儲在方法區(qū)的表現(xiàn)形式是靜態(tài)代碼塊執(zhí)行的結(jié)果存儲在方法區(qū),即初始化量存儲在方法區(qū)并被線程共享。

2 修飾成員變量

類中用static關(guān)鍵字修飾的成員變量稱為靜態(tài)成員變量,因為static不能修飾局部變量(為什么?),因此靜態(tài)成員變量也能稱為靜態(tài)變量。靜態(tài)變量跟代碼塊類似,在類加載到JVM內(nèi)存中,JVM會把靜態(tài)變量放入方法區(qū)并分配內(nèi)存,也由線程共享。訪問形式是:類名.靜態(tài)成員名。

public class StaticTest {
	public static void main(String[] args) {
		System.out.println(D.i);
		System.out.println(new D().i);
	}
}
class D {
	static {
		i = 2;
		System.out.println("D : 靜態(tài)代碼塊1");
	}
	static int i;
}

靜態(tài)變量存儲在類的信息中,且可以在線程間共享,那么它當(dāng)然也屬于該類的每個對象,因此可以通過對象訪問靜態(tài)變量,但編譯器并不支持這么做,且會給出警告。

注意:

一個類的靜態(tài)變量和該類的靜態(tài)代碼塊的加載順序。類會優(yōu)先加載靜態(tài)變量,然后加載靜態(tài)代碼塊,但有多個靜態(tài)變量和多個代碼塊時,會按照編寫的順序進(jìn)行加載。

class D {
	static {
		i = 2;
		System.out.println("D : 靜態(tài)代碼塊1");
	}
	static {
		i = 6;
		System.out.println("D : 靜態(tài)代碼塊2");
	}
	static int i;
}

可以想一下運行的結(jié)果。

靜態(tài)變量可以不用顯式的初始化,JVM會默認(rèn)給其相應(yīng)的默認(rèn)值。如基本數(shù)據(jù)類型的byte為0,short為0,char為\u0000,int為0,long為0L,float為0.0f,double為0.0d,boolean為false,引用類型統(tǒng)一為null。

靜態(tài)變量既然是JVM內(nèi)存中共享的且可以改變,那么對它的訪問會引起線程安全問題(線程A改寫的同時,線程B獲取它的值,那么獲取的是修改前的值還是修改后的值呢?),所以使用靜態(tài)變量的同時要考慮多線程情況。如果能確保靜態(tài)變量不可變,那么可以用final關(guān)鍵字一起使用避免線程安全問題;否則需要采用同步的方式避免線程安全問題,如與volatile關(guān)鍵字一起使用等。

static關(guān)鍵不能修飾局部變量,包括實例方法和靜態(tài)方法,不然就會與static關(guān)鍵字的初衷-共享相違背。

3 修飾方法

用static關(guān)鍵字修飾的方法稱為靜態(tài)方法,否則稱為實例方法。通過類名.方法名調(diào)用,但需要注意靜態(tài)方法可以直接調(diào)用類的靜態(tài)變量和其他靜態(tài)方法,不能直接調(diào)用成員變量和實例方法(除非通過對象調(diào)用)。

class D {
	static {
		i = 2;
		System.out.println("D : 靜態(tài)代碼塊");
	}
	static final int i;
	int j;
	
	static void method() {
		System.out.println(i);
		System.out.println(new D().j);
		
		method1();
		new D().method2();
	}
	
	static void method1() {
		System.out.println(i);
	}
	void method2() {
		System.out.println(i);
	}
}

注意:既然類的實例方法需要對象調(diào)用才能訪問,而靜態(tài)方法直接通過類名就能訪問,那么在不考慮部署服務(wù)器的情況下,一個類是如何開始執(zhí)行的呢?最大的可能就是通過“類名.靜態(tài)方法”啟動Java,而我定義那么多靜態(tài)方法,JVM又是如何知道主入口呢?

或許,你想到了main方法。

沒錯,就是main方法被Java規(guī)范定義成Java類的主入口。Java類的運行都由main方法開啟:

 public static void main(String[] args) {
	for (String arg : args) {   // 參數(shù)由外部定義
		System.out.println(arg);
	}}

但注意main并不是Java關(guān)鍵字,它只是一個規(guī)定的程序入口的方法名字;另外main方法可以重載。

注意:static關(guān)鍵字雖然不能修飾普通類,但可以用static關(guān)鍵字修飾內(nèi)部類使其變成靜態(tài)內(nèi)部類。static關(guān)鍵字本身的含義就是共享,而Java類加載到JVM內(nèi)存的方法區(qū),也是線程共享的,所以沒必要用static關(guān)鍵字修飾普通類。

4 靜態(tài)導(dǎo)入

在用import導(dǎo)入包或者類時,可以用static修飾包名或者類,表示靜態(tài)導(dǎo)入。靜態(tài)導(dǎo)入可以與動態(tài)導(dǎo)入放在一起比較來加深理解。

動態(tài)導(dǎo)入是當(dāng)你程序運行時需要new一個不在此包中的類的對象時,才會根據(jù)全路徑類名加載類;而靜態(tài)導(dǎo)入則是隨著類的加載而加載靜態(tài)導(dǎo)入的類,所以它是提前導(dǎo)入的。

public class StaticTest {
	static void method1() {
		System.out.println("static method1");
	}
	
	static void method2() {
		System.out.println("static method2");
	}
}

靜態(tài)導(dǎo)入:

import static com.starry.staticImport.StaticTest.method1;

public class Client {
	public static void main(String[] args) {
		method1();   // 
		StaticTest.method2();
	}
}

注意method1()是靜態(tài)導(dǎo)入,所以可以不需要通過類名訪問;而method2()沒有導(dǎo)入,則需要通過類名調(diào)用。那么什么時候需要靜態(tài)導(dǎo)入呢?

靜態(tài)導(dǎo)入常用于靜態(tài)方法以及含有靜態(tài)方法的類,枚舉類等的導(dǎo)入,可以在編譯階段確定導(dǎo)入類的信息或者方法信息。

static關(guān)鍵字的缺點

封裝是Java類的三大特性之一,也是面向?qū)ο蟮闹饕匦浴R驗椴恍枰ㄟ^對象,而直接通過類就能訪問類的屬性和方法,這有點破壞類的封裝性;所以除了Utils類,代碼中應(yīng)該盡量少用static關(guān)鍵字修飾變量和方法

關(guān)于static關(guān)鍵字作用是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI