<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          分享幾個(gè) Java static 關(guān)鍵字的常見誤區(qū)!

          共 9009字,需瀏覽 19分鐘

           ·

          2022-06-19 20:04

          你知道的越多,不知道的就越多,業(yè)余的像一棵小草!

          你來,我們一起精進(jìn)!你不來,我和你的競(jìng)爭(zhēng)對(duì)手一起精進(jìn)!

          編輯:業(yè)余草

          cnblogs.com/dolphin0520

          推薦:https://www.xttblog.com/?p=5347

          這兩天有一個(gè)網(wǎng)友,在微信群里討論面試情況。提到了一個(gè) static 關(guān)鍵字的問題,不少網(wǎng)友回答錯(cuò)誤了,我這里整理一篇文章分享給大家。不喜輕噴!

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

          1. static關(guān)鍵字的用途
          2. static關(guān)鍵字的誤區(qū)
          3. 常見的筆試面試題

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

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

          ?

          static 方法就是沒有 this 的方法。在 static 方法內(nèi)部不能調(diào)用非靜態(tài)方法,反過來是可以的。而且可以在沒有創(chuàng)建任何對(duì)象的前提下,僅僅通過類本身來調(diào)用 static 方法。這實(shí)際上正是 static 方法的主要用途。

          ?

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

          方便在沒有創(chuàng)建對(duì)象的情況下來進(jìn)行調(diào)用(方法/變量)。

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

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

          static 方法

          static 方法一般稱作靜態(tài)方法,由于靜態(tài)方法不依賴于任何對(duì)象就可以進(jìn)行訪問,因此對(duì)于靜態(tài)方法來說,是沒有 this 的,因?yàn)樗灰栏接谌魏螌?duì)象,既然都沒有對(duì)象,就談不上 this 了。并且由于這個(gè)特性,在靜態(tài)方法中不能訪問類的非靜態(tài)成員變量和非靜態(tài)成員方法,因?yàn)榉庆o態(tài)成員方法/變量都是必須依賴具體的對(duì)象才能夠被調(diào)用。

          但是要注意的是,雖然在靜態(tài)方法中不能訪問非靜態(tài)成員方法和非靜態(tài)成員變量,但是在非靜態(tài)成員方法中是可以訪問靜態(tài)成員方法/變量的。舉個(gè)簡(jiǎn)單的例子:

          static 方法

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

          MyObject.print2();

          此時(shí)對(duì)象都沒有,str2 根本就不存在,所以就會(huì)產(chǎn)生矛盾了。同樣對(duì)于方法也是一樣,由于你無法預(yù)知在 print1 方法中是否訪問了非靜態(tài)成員變量,所以也禁止在靜態(tài)成員方法中訪問非靜態(tài)成員方法。

          而對(duì)于非靜態(tài)成員方法,它訪問靜態(tài)成員方法/變量顯然是毫無限制的。

          因此,如果說想在不創(chuàng)建對(duì)象的情況下調(diào)用某個(gè)方法,就可以將這個(gè)方法設(shè)置為 static。我們最常見的 static 方法就是 main 方法,至于為什么 main 方法必須是 static 的,現(xiàn)在就很清楚了。因?yàn)槌绦蛟趫?zhí)行 main 方法的時(shí)候沒有創(chuàng)建任何對(duì)象,因此只有通過類名來訪問。

          static 變量

          static 變量也稱作靜態(tài)變量,靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有的對(duì)象所共享,在內(nèi)存中只有一個(gè)副本,它當(dāng)且僅當(dāng)在類初次加載時(shí)會(huì)被初始化。而非靜態(tài)變量是對(duì)象所擁有的,在創(chuàng)建對(duì)象的時(shí)候被初始化,存在多個(gè)副本,各個(gè)對(duì)象擁有的副本互不影響。

          static 成員變量的初始化順序按照定義的順序進(jìn)行初始化。

          static 代碼塊

          static 關(guān)鍵字還有一個(gè)比較關(guān)鍵的作用就是 用來形成靜態(tài)代碼塊以優(yōu)化程序性能。static 塊可以置于類中的任何地方,類中可以有多個(gè) static 塊。在類初次被加載的時(shí)候,會(huì)按照 static 塊的順序來執(zhí)行每個(gè) static 塊,并且只會(huì)執(zhí)行一次。

          為什么說 static 塊可以用來優(yōu)化程序性能,是因?yàn)樗奶匦裕褐粫?huì)在類加載的時(shí)候執(zhí)行一次。下面看個(gè)例子:

          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 是用來這個(gè)人是否是 1946-1964 年出生的,而每次 isBornBoomer 被調(diào)用的時(shí)候,都會(huì)生成 startDate 和 birthDate 兩個(gè)對(duì)象,造成了空間浪費(fèi),如果改成這樣效率會(huì)更好:

          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;
              }
          }

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

          static關(guān)鍵字的誤區(qū)

          static關(guān)鍵字會(huì)改變類中成員的訪問權(quán)限嗎?

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

          提示錯(cuò)誤Person.age 不可視,這說明 static 關(guān)鍵字并不會(huì)改變變量和方法的訪問權(quán)限。

          能通過 this 訪問靜態(tài)成員變量嗎?

          雖然對(duì)于靜態(tài)方法來說沒有 this,那么在非靜態(tài)方法中能夠通過 this 訪問靜態(tài)成員變量嗎?先看下面的一個(gè)例子,這段代碼輸出的結(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);
              }
          }
          33

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

          static能作用于局部變量么?

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

          常見的筆試面試題

          下面列舉一些面試筆試中經(jīng)常遇到的關(guān)于 static 關(guān)鍵字的題目,僅供參考,如有補(bǔ)充歡迎下方留言。

          下面這段代碼的輸出結(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");
              }
          }
          base static
          test static
          base constructor
          test constructor

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

          這段代碼的輸出結(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");
              }
          }
          test static
          myclass static
          person static
          person Test
          test constructor
          person MyClass
          myclass constructor

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

          這段代碼的輸出結(jié)果是什么?

          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 方法中沒有任何語句,但是還是會(huì)輸出,原因上面已經(jīng)講述過了。另外,static 塊可以出現(xiàn)類中的任何地方(只要不是方法內(nèi)部,記住,任何方法內(nèi)部都不行),并且執(zhí)行是按照 static 塊的順序執(zhí)行的。

          瀏覽 25
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91 国产 爽 黄 喷水 | 高清欧美猛交XXXX | 人体艺术香蕉视频 | 中文无码一区二区三区四区 | 黄色视频网站免费观看 |