實(shí)例解析Java關(guān)于static的作用
概述
只要是有學(xué)過Java的都一定知道static,也一定能多多少少說出一些作用和注意事項。如果已經(jīng)對static了如指掌的請點(diǎn)擊關(guān)閉按鈕,看下去也只是浪費(fèi)您寶貴時間而已。這篇隨筆只是個人的習(xí)慣總結(jié)。
為什么需要static?
有時候我們并不想去new一個對象,只是單純的想要調(diào)用一個函數(shù),并且希望這個函數(shù)不會與包含它的類的其他對象有所關(guān)聯(lián)。說得通俗點(diǎn),即使沒有創(chuàng)建對象,也能通過類本身來調(diào)用函數(shù)。
static靜態(tài)變量
被static修飾的變量屬于類變量,通過字面意思就說明了這個變量的歸屬(類),與之相對的是沒有被static修飾的成員變量,也稱為實(shí)例變量,說明這個變量是屬于某個具體的對象。
public class StaticDemo { private static int i = 50; private int j = 60; public static void main(String[] args) { StaticDemo staticDemo = new StaticDemo(); StaticDemo staticDemo1 = new StaticDemo(); //即使創(chuàng)建兩個對象,也都指向同一存儲空間 System.out.println(staticDemo.i); System.out.println(staticDemo1.i); //改變值 staticDemo.i = 52; System.out.println(staticDemo1.i); staticDemo.j = 65; staticDemo1.j = 70; System.out.println(staticDemo.j); System.out.println(staticDemo1.j); } }
輸出
50
50
52
65
70
通過上面的實(shí)例,我們很快看出他們的區(qū)別
- 靜態(tài)變量是屬于類的,只有一份存儲空間,是類之間共享的,牽一發(fā)而動全身,一處變,處處變。
- 實(shí)例變量屬于實(shí)例對象,創(chuàng)建幾次對象,就有幾份的成員變量(拷貝)。
static修飾的靜態(tài)函數(shù)
說到靜態(tài)函數(shù),就不得不提Java另一個關(guān)鍵詞this,指的是當(dāng)前的引用。意思是調(diào)用這個函數(shù)的對象,這意味著和static修飾的函數(shù)水火不容。被static修飾的函數(shù),不能出現(xiàn)this關(guān)鍵字,否則便會報錯。
去掉this,分別調(diào)用i或者j,會發(fā)現(xiàn)靜態(tài)函數(shù)調(diào)用非靜態(tài)資源時出錯。這是為什么?從JVM加載機(jī)制角度來說,靜態(tài)資源(被staitc修飾)是類在初始化的時候就加載的,而非靜態(tài)資源是new的時候加載的。類的初始化是早于new的,加載了say()的函數(shù)時,它并不認(rèn)識 j 這個成員變量,但對于非靜態(tài)函數(shù)來說,當(dāng)它加載時,靜態(tài)資源已經(jīng)加載完畢,所以它是認(rèn)識 i 這個靜態(tài)資源的。我們總結(jié)一下static修飾函數(shù)時的特點(diǎn)
- 靜態(tài)函數(shù)不能引用非靜態(tài)資源;
- 非靜態(tài)函數(shù)可以引用靜態(tài)資源;
- 靜態(tài)函數(shù)可以相互調(diào)用(只要引入所在包即可);
- 靜態(tài)函數(shù)沒有this,因為它不依附于任何對象。
現(xiàn)在,我們也能知道m(xù)ain函數(shù)為什么必須是static的,因為程序在執(zhí)行main函數(shù)時候,沒有創(chuàng)建任何對象,只是通過類名來訪問。
構(gòu)造函數(shù)是不是靜態(tài)函數(shù)?
《Java編程思想》提到“即使沒有顯示地使用static關(guān)鍵字,構(gòu)造器實(shí)際上也是靜態(tài)方法”。我至今不能確認(rèn)構(gòu)造器是不是靜態(tài)函數(shù),個人更偏向于不是。原因待會再闡述,先看個實(shí)例
public class StaticTest { private static int i; private int j; public StaticTest(int i,int j){ this.i = i; this.j = j; say1() } public void say1() { System.out.println("you age is" + i); System.out.println("you age is" + j); } public static void main(String[] args) { StaticTest staticTest = new StaticTest(4,5); StaticTest staticTest1 = new StaticTest(10,69); System.out.println(staticTest.i); System.out.println(staticTest.j); System.out.println(staticTest1.i); System.out.println(staticTest1.j); } }
輸出
you age is4
you age is5
you age is10
you age is69
10
5
10
69
實(shí)例中,確實(shí)改變了 i 的值,也符合靜態(tài)資源的定義,只有一份存儲空間。但構(gòu)造器里用了this,與我前文所說的static屬于類,不屬于任何對象,this屬于當(dāng)前引用對象互相矛盾,并且構(gòu)造函數(shù)還可以調(diào)用實(shí)例函數(shù)。一臉懵逼,這也是讓我感到困惑并且認(rèn)為構(gòu)造函數(shù)不是靜態(tài)函數(shù)的地方。如有周知,留言解惑,感謝。
靜態(tài)塊與非靜態(tài)塊
private static int i;
static
{
i = 5;
}
靜態(tài)塊是static的重要應(yīng)用之一,無函數(shù)名、作用域、返回值以及參數(shù),靜態(tài)代碼塊與靜態(tài)變量和靜態(tài)函數(shù)一樣,不論類被調(diào)用多少次,該區(qū)域代碼只在類初始化時第一次時執(zhí)行一次,并且嚴(yán)格按照靜態(tài)資源的定義順序執(zhí)行加載,與靜態(tài)函數(shù)區(qū)別在于一個主動一個被動。
{
System.out.println("我是靜態(tài)塊.");
}
非靜態(tài)塊,同樣無函數(shù)名,作用域,返回值以及參數(shù),非靜態(tài)代碼塊會在每次類被調(diào)用或者被實(shí)例化時執(zhí)行。
實(shí)例
public class StaticTest extends Father { public StaticTest() { System.out.println("我是StaticTest的構(gòu)造函數(shù)"); } { System.out.println("我是StaticTest的非靜態(tài)塊"); } static { System.out.println("我是StaticTest的靜態(tài)塊"); } public static void main(String[] args) { new StaticTest(); new StaticTest(); } } class Father { public Father() { System.out.println("我是Father構(gòu)造函數(shù)"); } { System.out.println("我是Father非靜態(tài)塊1"); } { System.out.println("我是Father非靜態(tài)塊2"); } static { System.out.println("我是Father靜態(tài)塊"); } }
輸出
我是Father靜態(tài)塊
我是StaticTest的靜態(tài)塊
我是Father非靜態(tài)塊1
我是Father非靜態(tài)塊2
我是Father構(gòu)造函數(shù)
我是StaticTest的非靜態(tài)塊
我是StaticTest的構(gòu)造函數(shù)
我是Father非靜態(tài)塊1
我是Father非靜態(tài)塊2
我是Father構(gòu)造函數(shù)
我是StaticTest的非靜態(tài)塊
我是StaticTest的構(gòu)造函數(shù)
加載順序 :父類靜態(tài)塊 > 子類靜態(tài)塊 > 父類非靜態(tài)塊 > 父類構(gòu)造函數(shù) > 子類非靜態(tài)塊 > 子類構(gòu)造函數(shù)
靜態(tài)代碼塊以及非靜態(tài)代碼塊都會在構(gòu)造函數(shù)前執(zhí)行,首次訪問時,靜態(tài)代碼塊會在非靜態(tài)代碼塊前執(zhí)行。
改變main函數(shù)
public static void main(String[] args)
{
}
輸出
我是Father靜態(tài)塊
我是StaticTest的靜態(tài)塊
靜態(tài)代碼塊在類加載時自動執(zhí)行,非靜態(tài)代碼塊是在創(chuàng)建對象時自動執(zhí)行的代碼,不創(chuàng)建對象不執(zhí)行該類的非靜態(tài)代碼塊。
靜態(tài)導(dǎo)入
靜態(tài)導(dǎo)入是jdk5引入的新特性,有時我們在實(shí)際應(yīng)用中,并不需要整個jar包都導(dǎo)入,而只是想使用某部分函數(shù)。提高代碼的閱讀性,更好的理解程序。
import static java.lang.System.out; public class StaticTest { public static void main(String[] args) { out.println("import static測試"); System.out.println("import static測試"); } }
輸出
import static測試
import static測試
會發(fā)現(xiàn),兩者輸出是沒有區(qū)別的,但是我們少寫了System. 雖然允許這么使用,但在實(shí)際開發(fā)中,我很少發(fā)現(xiàn)有同事這么做,主要是不利于理解,但好處是如果頻繁用這個類,可以少很多的類名。
===============================================================
如發(fā)現(xiàn)錯誤,請及時留言,lz及時修改,避免誤導(dǎo)后來者。感謝!??!
相關(guān)文章
java獲取request中的參數(shù)以及java解析URL問號后的參數(shù)
這篇文章主要介紹了java獲取request中的參數(shù)以及java解析URL問號后的參數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12Java 數(shù)據(jù)結(jié)構(gòu)鏈表操作實(shí)現(xiàn)代碼
這篇文章主要介紹了Java 數(shù)據(jù)結(jié)構(gòu)鏈表操作的相關(guān)資料,并附實(shí)例代碼,需要的朋友可以參考下2016-10-10基于SpringBoot整合SSMP案例(開啟日志與分頁查詢條件查詢功能實(shí)現(xiàn))
這篇文章主要介紹了基于SpringBoot整合SSMP案例(開啟日志與分頁查詢條件查詢功能實(shí)現(xiàn)),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋參考下吧2023-11-11Java經(jīng)典排序算法之插入排序代碼實(shí)例
這篇文章主要介紹了Java經(jīng)典排序算法之插入排序代碼實(shí)例,插入排序是一種最簡單直觀的排序算法,它的工作原理是通過構(gòu)建有序序列,對于未排序數(shù)據(jù),在已排序序列中從后向前掃描,找到相應(yīng)位置并插入,需要的朋友可以參考下2023-10-10Java中l(wèi)ong類型與Long類型的區(qū)別和大小比較詳解
這篇文章主要給大家介紹了Java中l(wèi)ong類型與Long類型區(qū)別和大小比較的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11MyBatis關(guān)閉一級緩存的兩種方式(分注解和xml兩種方式)
這篇文章主要介紹了MyBatis關(guān)閉一級緩存的兩種方式(分注解和xml兩種方式),mybatis默認(rèn)開啟一級緩存,執(zhí)行2次相同sql,但是第一次查詢sql結(jié)果會加工處理這個時候需要關(guān)閉一級緩存,本文給大家詳細(xì)講解需要的朋友可以參考下2022-11-11