Java中的static關鍵字解析

  static關鍵字是很多朋友在編寫代碼和閱讀代碼時碰到的比較難以理解的一個關鍵字,也是各大公司的面試官喜歡在面試時問到的知識點之一。下面就先講述一下static關鍵字的用法和平常容易誤解的地方,最后列舉了一些面試筆試中常見的關于static的考題。以下是本文的目錄大綱:

  一.static關鍵字的用途

  二.static關鍵字的誤區

  三.常見的筆試面試題

  若有不正之處,希望諒解并歡迎批評指正。

  請尊重作者勞動成果,轉載請標明原文鏈接:

  http://www.cnblogs.com/dolphin0520/p/3799052.html

一.static關鍵字的用途

  在《Java編程思想》P86頁有這樣一段話:

  “static方法就是沒有this的方法。在static方法內部不能調用非靜態方法,反過來是可以的。而且可以在沒有創建任何對象的前提下,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途。”

  這段話雖然只是說明了static方法的特殊之處,但是可以看出static關鍵字的基本作用,簡而言之,一句話來描述就是:

  方便在沒有創建對象的情況下來進行調用(方法/變量)。

  很顯然,被static關鍵字修飾的方法或者變量不需要依賴于對象來進行訪問,只要類被加載了,就可以通過類名去進行訪問。

  static可以用來修飾類的成員方法、類的成員變量,另外可以編寫static代碼塊來優化程序性能。

1)static方法

  static方法一般稱作靜態方法,由于靜態方法不依賴于任何對象就可以進行訪問,因此對于靜態方法來說,是沒有this的,因為它不依附于任何對象,既然都沒有對象,就談不上this了。并且由于這個特性,在靜態方法中不能訪問類的非靜態成員變量和非靜態成員方法,因為非靜態成員方法/變量都是必須依賴具體的對象才能夠被調用。

  但是要注意的是,雖然在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,但是在非靜態成員方法中是可以訪問靜態成員方法/變量的。舉個簡單的例子:

  在上面的代碼中,由于print2方法是獨立于對象存在的,可以直接用過類名調用。假如說可以在靜態方法中訪問非靜態方法/變量的話,那么如果在main方法中有下面一條語句:

  MyObject.print2();

  此時對象都沒有,str2根本就不存在,所以就會產生矛盾了。同樣對于方法也是一樣,由于你無法預知在print1方法中是否訪問了非靜態成員變量,所以也禁止在靜態成員方法中訪問非靜態成員方法。

  而對于非靜態成員方法,它訪問靜態成員方法/變量顯然是毫無限制的。

  因此,如果說想在不創建對象的情況下調用某個方法,就可以將這個方法設置為static。我們最常見的static方法就是main方法,至于為什么main方法必須是static的,現在就很清楚了。因為程序在執行main方法的時候沒有創建任何對象,因此只有通過類名來訪問。

  另外記住,即使沒有顯示地聲明為static,類的構造器實際上也是靜態方法。

2)static變量

  static變量也稱作靜態變量,靜態變量和非靜態變量的區別是:靜態變量被所有的對象所共享,在內存中只有一個副本,它當且僅當在類初次加載時會被初始化。而非靜態變量是對象所擁有的,在創建對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。

  static成員變量的初始化順序按照定義的順序進行初始化。

3)static代碼塊

  static關鍵字還有一個比較關鍵的作用就是 用來形成靜態代碼塊以優化程序性能。static塊可以置于類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,并且只會執行一次。

  為什么說static塊可以用來優化程序性能,是因為它的特性:只會在類加載的時候執行一次。下面看個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
class?Person{
????private?Date birthDate;
?????
????public?Person(Date birthDate) {
????????this.birthDate = birthDate;
????}
?????
????boolean?isBornBoomer() {
????????Date startDate = Date.valueOf("1946");
????????Date endDate = Date.valueOf("1964");
????????return?birthDate.compareTo(startDate)>=0?&& birthDate.compareTo(endDate) <?0;
????}
}

  isBornBoomer是用來這個人是否是1946-1964年出生的,而每次isBornBoomer被調用的時候,都會生成startDate和birthDate兩個對象,造成了空間浪費,如果改成這樣效率會更好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class?Person{
????private?Date birthDate;
????private?static?Date startDate,endDate;
????static{
????????startDate = Date.valueOf("1946");
????????endDate = Date.valueOf("1964");
????}
?????
????public?Person(Date birthDate) {
????????this.birthDate = birthDate;
????}
?????
????boolean?isBornBoomer() {
????????return?birthDate.compareTo(startDate)>=0?&& birthDate.compareTo(endDate) <?0;
????}
}

  因此,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行。

二.static關鍵字的誤區

1.static關鍵字會改變類中成員的訪問權限嗎?

  有些初學的朋友會將java中的static與C/C++中的static關鍵字的功能混淆了。在這里只需要記住一點:與C/C++中的static不同,Java中的static關鍵字不會影響到變量或者方法的作用域。在Java中能夠影響到訪問權限的只有private、public、protected(包括包訪問權限)這幾個關鍵字。看下面的例子就明白了:

  提示錯誤"Person.age 不可視",這說明static關鍵字并不會改變變量和方法的訪問權限。

2.能通過this訪問靜態成員變量嗎?

  雖然對于靜態方法來說沒有this,那么在非靜態方法中能夠通過this訪問靜態成員變量嗎?先看下面的一個例子,這段代碼輸出的結果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
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);
????}
}

?

33

  這里面主要考察隊this和static的理解。this代表什么?this代表當前對象,那么通過new Main()來調用printValue的話,當前對象就是通過new Main()生成的對象。而static變量是被對象所享有的,因此在printValue中的this.value的值毫無疑問是33。在printValue方法內部的value是局部變量,根本不可能與this關聯,所以輸出結果是33。在這里永遠要記住一點:靜態成員變量雖然獨立于對象,但是不代表不可以通過對象去訪問,所有的靜態方法和靜態變量都可以通過對象訪問(只要訪問權限足夠)。

3.static能作用于局部變量么?

  在C/C++中static是可以作用域局部變量的,但是在Java中切記:static是不允許用來修飾局部變量。不要問為什么,這是Java語法的規定。

三.常見的筆試面試題

  下面列舉一些面試筆試中經常遇到的關于static關鍵字的題目,僅供參考,如有補充歡迎下方留言。

1.下面這段代碼的輸出結果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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");
????}
}
base static
test static
base constructor
test constructor

  至于為什么是這個結果,我們先不討論,先來想一下這段代碼具體的執行過程,在執行開始,先要尋找到main方法,因為main方法是程序的入口,但是在執行main方法之前,必須先加載Test類,而在加載Test類的時候發現Test類繼承自Base類,因此會轉去先加載Base類,在加載Base類的時候,發現有static塊,便執行了static塊。在Base類加載完成之后,便繼續加載Test類,然后發現Test類中也有static塊,便執行static塊。在加載完所需的類之后,便開始執行main方法。在main方法中執行new Test()的時候會先調用父類的構造器,然后再調用自身的構造器。因此,便出現了上面的輸出結果。

2.這段代碼的輸出結果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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");
????}
}
復制代碼
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
復制代碼

  類似地,我們還是來想一下這段代碼的具體執行過程。首先加載Test類,因此會執行Test類中的static塊。接著執行new MyClass(),而MyClass類還沒有被加載,因此需要加載MyClass類。在加載MyClass類的時候,發現MyClass類繼承自Test類,但是由于Test類已經被加載了,所以只需要加載MyClass類,那么就會執行MyClass類的中的static塊。在加載完之后,就通過構造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,因此會執行Test中的Person person = new Person(),而Person類還沒有被加載過,因此會先加載Person類并執行Person類中的static塊,接著執行父類的構造器,完成了父類的初始化,然后就來初始化自身了,因此會接著執行MyClass中的Person person = new Person(),最后執行MyClass的構造器。

3.這段代碼的輸出結果是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
public?class?Test {
?????
????static{
????????System.out.println("test static 1");
????}
????public?static?void?main(String[] args) {
?????????
????}
?????
????static{
????????System.out.println("test static 2");
????}
}
test static 1
test static 2

  雖然在main方法中沒有任何語句,但是還是會輸出,原因上面已經講述過了。另外,static塊可以出現類中的任何地方(只要不是方法內部,記住,任何方法內部都不行),并且執行是按照static塊的順序執行的。

  參考資料:

  http://lavasoft.blog.51cto.com/62575/18771/

  http://www.51cto.com/specbook/24/35011.htm

  http://blog.csdn.net/zhu_apollo/article/details/1888219

  http://blog.sina.com.cn/s/blog_70b845780100n9zz.html

  http://hi.baidu.com/yuiezt/item/b71ff5fbfe9c385cc8f3370d

  http://bbs.csdn.net/topics/330251070

  http://yezixingchen.iteye.com/blog/1597186

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284188.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284188.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284188.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

微信公眾號授權登錄后報redirect_uri參數錯誤的問題

在進行微信公眾號二次開發的時候&#xff0c;需要通過授權碼模式來進行微信授權。比如&#xff0c;在進行登錄的時候&#xff0c;用戶點擊了登錄按鈕&#xff0c;然后彈出一個授權框&#xff0c;用戶點擊同意后&#xff0c;就可以獲取用戶的OpenId等信息了。這篇文章主要分享下…

【GlobalMapper精品教程】022:根據一個字段屬性值批量計算另一個字段屬性值(地類名稱求地類編碼)

項目中通常需要根據一個字段屬性值的不同,批量計算另一個字段屬性值(如根據地類名稱求地類編碼),根據權屬地物名稱給權屬地物編碼批量賦值等,本文講解在屬性表中根據代碼批量實現方法。 參考閱讀: 【ArcGIS風暴】ArcGIS 10.2字段計算器(Field Calculator)批量條件賦值用…

[轉]【讀書筆記】《俞軍產品方法論》——產品經理的枕邊書

作者簡介 俞軍&#xff0c;1997年畢業于同濟大學化學系。曾任百度產品副總裁、首席產品架構師&#xff0c;網名“搜索引擎9238”&#xff0c;有“百度貼吧之父”之稱。滴滴前高級產品副總裁。 內容簡介 摘抄語錄 我的產品潛力和優勢大約只來自三方面&#xff1a;第一&#xff0…

linux批量分發必會面試題,通過郵件反饋結果。

請準備三臺linux機器為別為A,B,C,要求實現以下內容1、用自己的名字用戶完成一把鑰匙開多把鎖&#xff08;A&#xff0c;鑰匙&#xff0c;B,C鎖&#xff09;的免密碼登錄部署場景該題在生產環境中的用途為&#xff1b;批量分發數據&#xff0c;批量發布程序代碼&#xff0c;批量…

【GlobalMapper精品教程】023:Excel數據通過相同字段連接到屬性表中(氣溫降水連接到氣象臺站)

globalmapper中也可以將Excel數據通過相同字段連接到屬性表中。本文講解將氣溫降水連接到氣象臺站點圖層中。 文章目錄 一、加載氣象臺站數據二、掛接氣溫降水數據一、加載氣象臺站數據 globalmapper中根據坐標生成點的方法,前面的文章有所說明: 【GlobalMapper精品教程】0…

記一次 .NET 某智慧物流WCS系統CPU爆高分析

一&#xff1a;背景 1. 講故事哈哈&#xff0c;再次見到物流類軟件&#xff0c;上個月有位朋友找到我&#xff0c;說他的程序出現了 CPU 爆高&#xff0c;讓我幫忙看下什么原因&#xff0c;由于那段時間在苦心研究 C&#xff0c;分析和經驗分享也就懈怠了&#xff0c;今天就給大…

c#調用存儲過程查詢表并返回影響的行數

// 在此處放置用戶代碼以初始化頁面 String DBConnStr; DataSet MyDataSet new DataSet(); SqlDataAdapter DataAdapter new SqlDataAdapter(); DBConnStr "server192.168.2.120,2433;databaseDB_test;uidsa;pwd43g"; Sq…

采用Atlas+Keepalived實現MySQL讀寫分離、讀負載均衡【轉載】

文章 原始出處 &#xff1a;http://sofar.blog.51cto.com/353572/1601552 一、基礎介紹 1、背景描述 目前我們的高可用DB的代理層采用的是360開源的Atlas&#xff0c;從上線以來&#xff0c;已穩定運行2個多月。無論是從性能上&#xff0c;還是穩定性上&#xff0c;相比其他開…

vscode搭建go開發環境

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、安裝goLang二.配置環境變量三、vscode安裝插件四.安裝golang依賴五.新建go文件前言 能用golang就用golang..這配置很麻煩 提示&#xff1a;以下是本篇文章正…

【GlobalMapper精品教程】024:批量高效實現多種數據格式互轉的方法

globalmapper批量高效實現多種數據格式互轉的方法。 文章目錄一、批量格式轉換二、格式轉換形式舉例一、批量格式轉換 選擇原文件類型&#xff1a; 選擇文件類型&#xff1a; 在源文件列表中添加需要轉換的文件或者文件夾&#xff0c;指定目標文件目錄&#xff0c;文件名稱和投…

基于 WeihanLi.Npoi 實現excel導入時純漢字的日期轉換

基于 WeihanLi.Npoi 實現excel導入時純漢字的日期轉換Intro前段時間有位小伙伴在 Github 上提了一個 “不能識別純漢字的日期格式” issue二〇二二年一月一日 格式的日期單元格識別不出來會變成&#xff0c;0001/1/1 0:00:00 如何讓它能夠識別出來呢&#xff0c;基于 InputForm…

寒假學習筆記(3)

2018.2.9 類 class class 類名{}&#xff1b;類似與結構體&#xff1b;類的實質是一種數據類型&#xff0c;類似于int、char等基本類型&#xff0c;不同的是它是一種復雜的數據類型。因為它的本質是類型&#xff0c;而不是數據&#xff0c;所以不存在于內存中&#xff0c;不能被…

十個模型,總結產品經理溝通方法論

編輯導語&#xff1a;毫不夸張地說溝通占據了產品經理日常工作內容的40%&#xff0c;高效溝通往往能讓事情事半功倍。本文作者結合溝通方法與具體溝通情景講解了如何高效溝通&#xff0c;一起來看看吧&#xff01; 目錄 一、為什么要學會溝通 二、溝通模型 1. PREP原則&…

【Alpha】開發日志Day8-0719

最近幾天是攻堅階段&#xff0c;大家配合得越來越嫻熟了~ 以下是各位的每日小結&#xff1a; 姓名今日完成任務遇到的問題陳劼博寫了一個PPT播放界面&#xff0c;后來發現師兄其實已經完成了黃志華嘗試解決上傳問題,但是沒有成功&#xff1b;寫了一個修改表單的代碼,發現前端寫…

MySQL--字符集

1.字符集概述 簡單的說字符集就是一套文字符號及其編碼、比較規則的集合20世紀60年代初期&#xff0c;美國標準化組織ANSI發布了第一個計算機的字符集ASCII(American Standard Code for Information Interchange)&#xff0c;后來進一步變成了國際標準ISO-646。這個字符集采用7…

【Globalmapper中文入門到精通系列實驗圖文教程】(附配套實驗數據持續更新)

【Globalmapper中文版入門到精通系列實驗圖文教程】&#xff08;附配套實驗數據持續更新&#xff09; 文章目錄一、專欄簡介二、文章目錄三、數據目錄四、傳送門一、專欄簡介 本專欄為GlobalMapper中文入門實戰精品教程&#xff0c;內容主要涉及&#xff1a;Globalmapper23軟件…

【GlobalMapper精品教程】025:影像數據集的建立與巧妙使用

GlobalMapper影像數據集類似于金字塔,作用是提高大量影像的加載與顯示速度,還可批量進行一系列設置。本文的配套數據為data025.rar。 文章目錄 1. 建立影像數據集2. 影像數據集的使用1. 建立影像數據集 (1)點擊【文件】→【創建新地圖目錄】。 (2)選擇影像數據集存放路徑…

使用xUnit為.net core程序進行單元測試(3)

第1部分: http://www.cnblogs.com/cgzl/p/8283610.html 第2部分: http://www.cnblogs.com/cgzl/p/8287588.html 請使用這個項目作為練習的開始: https://pan.baidu.com/s/1ggcGkGb 測試的分組 打開Game.Tests里面的BossEnemyShould.cs, 為HaveCorrectPower方法添加一個Trait屬性…

war部署到tomcat

gs-rest-service-0.1.0.war復制到tomcat-9.0.0.M17\webapps\打開server.xml&#xff0c;這Host節點&#xff0c;加入<Context path"/gs" docBase"gs-rest-service-0.1.0.war" debug"0" privileged"true"/> gs相當于虛擬目錄&…

C# Thread IsBackground作用

背景之前在做一個定時下載任務的時候&#xff0c;使用的是一個主線程在執行任務&#xff1b;后面需求調整了&#xff0c;需要在啟用一個子線程執行優先級更高的單獨通道下載。于是下意識的這么做 new Thread//創建后臺線程Thread bThread new Thread(new ThreadStart(backgrou…