本文連接地址:http://www.javashuo.com/article/p-zenshsfg-kh.htmlhtml
No enclosing instance of type
SomeClass
is accessible. Must qualify the allocation with an enclosing instance of typeSomeClass
(e.g.x.new A()
wherex
is an instance ofSomeClass
).java
拿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
的內類。
而後錯誤就發生了……eclipse
若是已經瞭解了靜態的內容,請自行跳轉至「靜態成員說完了,那跟這你遇到的這個問題有什麼關係呢??」子節函數
好吧,其實說到底都是main
的static
修飾惹的禍。
咱們知道static
的成員也好,類也好,所謂的「靜態」其實說的都是「爲整個程序所共享」的意思,說的直白一點,static
的東西都很是的「大公無私」。
固然,其實我寫C#寫的比較多,對Java的規則還不是很瞭解,彷佛Java並不像C#那樣容許public static class SomeClass
,因此對於Java而言更多的是針對靜態成員討論的。this
做爲一個大公無私的內容,static
的成員裏面除了本身再構造一些臨時對象之外,直接援引的類、函數都不能是爲某一對象所特有的。code
不,這裏說的「特有」並非這個意思,或許我換個詞語會更好一些——對象「個性」的屬性。orm
打住,我知道你要問這件事,因此我這裏舉個糖炒栗子:
好比說類Gold
被定義爲:htm
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
是「個性」的,這個結果固然也就可能彼此不一樣。
而Rise
和Reduce
這兩個函數,它們要修改的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
的,那麼也就意味着這不是一種「個性」的行爲,而是「共性」的行爲,這也就是說:
這種行爲並不能由某一個體單獨執行,必須賭上全種族的命運,以種族的名義,去吧!!!
因此,若是不但願金價被某一個金塊干擾的話,Rise
和Reduce
也得是static
的:
public static void Rise(float price) //提高黃金單價,增長price元 { xau += price; } public static void Reduce(float price) // 下降黃金單價,減小price元 { xau -= price; }
這樣一來,Rise
和Reduce
就必須以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
全體的oz
,每一個金子都有本身的oz
,因此這個時候調用Gold.GetPrice()
,程序本身也不知道該返回誰的oz
,因此這樣是不能夠的。
拿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
的內類。
而後錯誤就發生了……
請注意畫線部分!!!
Java裏面main
函數強制具有這些修飾:public static void
,也就是說main
理所應當的是個靜態成員。
可是,請注意,main
裏面試圖引入了MainJWindowListener
這個內類並試圖調用構造函數進行構造,但是,MainJWindowListener
只是個缺省訪問級別的普通動態內類,這就是問題所在了。
這裏基於使用了Swing這個事實,解決方案有兩種,其中一種是推薦的,而另一種是通用的。
推薦的方法是用於根治在Swing下發生這種問題的一種重構代碼的思路,這種方法規避了在靜態成員中進行動態內類(這裏面動態內類主要指事件偵聽器)的引用。
通用的方法是針對咱們遇到的這個問題,經過修改代碼使得靜態成員可以調用動態內類,這裏時刻注意一點,內類由於不是靜態的,這意味着內類的構造必須在一個外部類(一個非靜態類)實例的範疇下進行。
考慮到我這裏的情景,我是要給窗口註冊一下窗口關閉的動做,也就是爲關閉按鈕添加事件偵聽器。
可是實際狀況是,基本上只要是這個MainJFrame
窗口,我都但願它註冊這個關閉按鈕的事件偵聽器。因此這個過程徹底能夠不在主函數裏進行。
而一個非靜態類,不管長成什麼樣子,其構造函數永遠也不會是static
的,因此事件偵聽的註冊徹底能夠放到構造函數裏去作:
public MainJFrame(String caption) { super(caption); //....Some initial actions...// this.addWindowListener(new MainJWindowListener()); }
而後main
函數只須要負責構造之就能夠了:
public static void main(String args[]) { //..Others..// MainJFrame frmBase = new MainJFrame(); //..Others..// }
這是個很是一勞永逸且合乎邏輯的作法,由於就算有多個MainJFrame
,咱們通常都會但願對用戶行爲的反饋是一致的,也就是說實際上全部的MainJFrame
都會被配備相同的事件偵聽器,既然如此的話放到構造函數統一隨着構造的時候執行是再好不過的了。
推薦的方法裏面規避了在靜態成員中調用這個內部類,轉到一個非靜態成員中進行,並且事實上證實「效果拔羣」。
可是說到底「效果拔羣」也只是對這類情形「拔羣」,假使咱們非要這麼作,好比說我非要在多個MainJFrame
作不一樣的事件偵聽處理,那就不該該寫在構造函數當中,由於這不是統一的構造流程,無法寫進一個函數裏。
也就是說,咱們非得要在main
函數裏作偵聽綁定,由於main
函數強制具備static
性質,而MainJWindowListener
不是static
的因此像這樣是不能夠的:
public static void main(String args[]) { MainJFrame frmBase = new MainJFrame("Hello Swing"); frmBase.setBackground(Color.white); frmBase.setVisible(true); // 不行!!!MainJWindowListener不是靜態的!!! frmBase.addWindowListener(new MainJWindowListener()); }
也就是說,MainJWindowListener
必須跟着一個MainJFrame
的實例裏面才能夠構造,那麼咱們非要找一個MainJFrame
實例mjfinstance
不可,而後再new mjfinstance.MainJWindowListener()
……
……巧了,這不是有麼??frmBase
不就是一個MainJFrame
麼??因此把這一句改爲:
frmBase.addWindowListener(new frmBase.MainJWindowListener());
就能夠了。