­

Java中的static(1)【持續更新】——關於Eclipse的No enclosing instance of type … 錯誤的理解和改正

  • 2019 年 10 月 7 日
  • 筆記

No enclosing instance of type SomeClass is accessible. Must qualify the allocation with an enclosing instance of type SomeClass (e.g. x.new A() where x is an instance of SomeClass).

這是怎麼發現的??

拿Eclipse編寫Java的AWT/Swing程序時,編寫了一個public class MainFrame extends JFrame然後在其中放入一個主函數寫入了如下內容:

public static void main(String args[])  {      MainJFrame frmBase = new MainJFrame("Hello Swing");      frmBase.setBackground(Color.white);      frmBase.setVisible(true);      frmBase.addWindowListener(new MainJWindowListener());    // <--- Error occured here !!!  }

也就是我在主函數創建了窗口之後想要繼續在主函數里為frmBase這個JFrame窗口添加窗口監聽器(class MainJWindowListener implements WindowListener),其中MainJWindowListener作為MainFrame內類
然後錯誤就發生了……

為什麼會這樣呢??

好吧,其實說到底都是mainstatic修飾惹的禍。
我們知道static的成員也好,類也好,所謂的「靜態」其實說的都是「為整個程序所共享」的意思,說的直白一點,static的東西都非常的「大公無私」
當然,其實我寫C#寫的比較多,對Java的規則還不是很了解,似乎Java並不像C#那樣允許public static class SomeClass,所以對於Java而言更多的是針對靜態成員討論的。

作為一個大公無私的內容,static的成員裏面除了自己再構造一些臨時對象以外,直接援引的類、函數都不能為某一對象所特有的。

不能為某一對象所特有??但是既然是定義到類里的屬性,那類的所有對象不是都有這個屬性么??

不,這裡說的「特有」並不是這個意思,或許我換個詞語會更好一些——對象「個性」的屬性。

個性化……但這是什……

打住,我知道你要問這件事,所以我這裡舉個糖炒栗子:
比如說類Gold被定義為:

public class Gold  {      // Properties      private static float xau = 1504.35f;  // 金單價,也就是每盎司黃金在國際市場的價格,我隨便編的數請別在意……      private float oz;    // 該黃金實例(理解成金塊金錠金碎末金戒指金項鏈都可以)的質量(盎司數)        // Constructor      public Gold(float oz)      {          this.oz = oz;      }      // Methods ...  }

我們看到金單價xau是靜態的,因為無論那個金子多沉,長成什麼樣子,金單價對所有金子都是一樣的,而且當xau變動的時候,所有Gold的價格也都會隨着xau變動。所以這種屬性就不具備「個性」,因為你用我用大家一起用,也就是說,這是全體的「共性」。

而重量oz就不一樣了,一座金山(Kingsoft)可能有1e+xxx的oz,而一個金粒可能只有1e-xxx的oz,我可能用一個new Gold(1e+500)表示我構建了一個黃金星球,我也可能用new Gold(1e-500)表示我構造了一個金分子之類的。
但總之,他們都是Gold,他們都有oz,可是每個人的oz都不一樣,這就是個性

你有Freestyle嘛

我們接下來再看看它的方法想定義些什麼(但我現在暫時不定義):

public class Gold  {      // Properties ...        // Constructor ...        // Methods      // GetPrice() 能夠獲得該金塊的具體價格,按金單價*盎司數計算      // Rise(float price) 提升黃金單價,增加price元      // Reduce(float price) 降低黃金單價,減少price元      // ...  }

先看這些函數,很明顯我們能看出一些規律:
GetPrice這種函數,它的結果是「個性」的,xau*oz當中oz是「個性」的,這個結果當然也就可能彼此不同。
RiseReduce這兩個函數,它們要修改的xau是共性的,而且僅僅牽涉到「共性」,也就是說,它們是能夠影響整個黃金國度每一個金子的命運的函數。

嗨,要是我嘛,全都定義成平常的就可以了吧

啊,確實可以,因為非靜態的成員能夠訪問類內所有的其他成員,無所謂靜態和非靜態。
當然,對於GetPrice來說,這無所謂,而且其結果本身就是「個性」的:

public class Gold  {      // Properties ...        // Constructor ...        // Methods      public float GetPrice() // 能夠獲得該金塊的具體價格,按金單價*盎司數計算      {          return xau*oz;      }      public void Rise(float price) //提升黃金單價,增加price元      {          xau += price;      }      public void Reduce(float price) // 降低黃金單價,減少price元      {          xau -= price;      }      // ...  }

這麼寫的話當然沒有問題,不犯任何語法錯誤而且編譯是通過的,而且你只要實例化一個金子你也確實能夠正確地調用這些函數並得到正確的結果。
像這樣:

public void main(String args[]) //主函數,在哪個類里就別管了  {      Gold gNugget = new Gold(0.01f);      System.out.println(String.format("%.2f", gNugget.GetPrice()));      gNugget.Rise(10.0f);      System.out.println(String.format("%.2f", gNugget.GetPrice()));      gNugget.Reduce(20.0f);      System.out.println(String.format("%.2f", gNugget.GetPrice()));  }

輸出結果:

15.04  15.14  14.94

結果確實沒問題

……當然你也可以弄好多個金子這麼玩……

只不過……

gNugget.Rise()或者gMountain.Reduce()被調用的時候,所有金子(當然包含它們自身)都是受到影響的。
想像一下:

gNugget.Reduce(1000.0f);

結果一個小小的金粒導致了黃金市場遭受了慘重的金融危機,你不覺得這個小金粒的能耐忒大了點么??
當然,這也就同將Rise()/Reduce()改成public也差不多了。

好吧,是挺危險的,那我不希望這樣,該怎麼辦呢

一個普通的,不是static的函數,意味着它是一種「個性」的行為,這也就是說:

這種行為誰都可以做,想來就來我行我秀u can u up

當然,如果一個函數被聲明為static的,那麼也就意味着這不是一種「個性」的行為,而是「共性」的行為,這也就是說:

這種行為並不能由某一個體單獨執行,必須賭上全種族的命運,以種族的名義,去吧!!!

所以,如果不希望金價被某一個金塊干擾的話,RiseReduce也得是static的:

    public static void Rise(float price) //提升黃金單價,增加price元      {          xau += price;      }      public static void Reduce(float price) // 降低黃金單價,減少price元      {          xau -= price;      }

這樣一來,RiseReduce就必須以Gold.Rise()Gold.Reduce()調用,而不能讓Gold的實例來調用,也就是說,這一舉措會導致下面的語句出錯:

gNugget.Rise(10.0f);  gNugget.Reduce(20.0f);

因為這兩個函數是「共性」的,想漲價降價你一個小小的gNugget說了不算的,必須是以Gold全體的名義來說:Gold.Rise()

當然,共性行為也會有這樣的約束,比如,共性的行為不允許引入個性的內容(書面上來說就是靜態方法中不允許調用非靜態的屬性和方法和內部類),因為如果一個行為牽扯到個性的因素,那麼它就不能以這個類全體的名義去做,比如我把GetPrice改成static的就會出錯:

    public static float GetPrice() // 不行!!!!      {          return xau*oz;      }

因為這個時候調用Gold.GetPrice()的時候,並不存在屬於Gold全體的oz,因為一個金子一個樣。