2014年5月19日 星期一

java--Cannot refer to a non-final variable XXX inside an inner class defined in a different method

前幾天使用java,總是出現一個與final變數有關的錯誤,雖然知道如何修正,但卻不知原理。最近對java熟悉了一些,終於知道問題所在,特別加以記錄。

1 public class MainFrame extends JFrame {
2 private JTextField textInput;

3 public MainFrame() {
4 textInput = new JTextField();
5 JButton btnOK= JButton("");
6 btnOK.getModel();
7 btnOK.addActionListener(new ActionListener() {

8 public void actionPerformed(ActionEvent arg0) {
9 Searcher searcher = new Searcher();

10 if (arg0.getSource()==btnOK)
11 try {
12 searcher.search("contents", textInput.getText());
13 }
14 } catch (IOException | ParseException e) {
15 e.printStackTrace();
16 } } }); }
}

第8行的函數actionPerformed() 是位於第3行public MainFrame() 的函數內,如果第5行JButton btnOK= JButton()是在MainFrame()的函數內定義,那麼在第10行if (arg0.getSource()==btnOK) ,這裡使用到btnOK的話,在編寫java程式時就會出現關於使用final 變數的錯誤如下

Cannot refer to a non-final variable btnOK inside an inner class defined in a different method
這句話的意思是說在不同方法(method)中定義的內部類別(inner class)不可以參考到非final的變數。

究其原因,在於第10行用到的內部類別的區域變數btnOK並不是真的與第5行的btnOK是同一個變數,而是在內部類別中被複製一份出來,由於是複本,即便您在內部類別中對btnOK作了修改,也不會影響原來真正的變數,事實上您也通不過編譯器的檢查,因為編譯器要求您加上"final"關鍵字,這樣您就不能在內部類別中改變btnOK的值。
另一個方法是把btnOK變全域的變數,這樣不管在內部類別或外部都用到同一個變數,就不存在複本的問題了。

綜合以上,有兩個解決方法:
1.在第5行JButton btnOK= JButton("")的地方,改成 final JButton btnOK= JButton("")
2.btnOK不要在MainFrame()的函數內定義,而是在所有函數的外圍,在class本體內定義,改成如下範例:
在第2行下面增加private JButton btnOK;

至於要使用final變數的原因,更詳細請看
http://hi.baidu.com/_sherry_liu/item/58140f7387c28d336dc37c9e
關於 final 的用法,原理,基本常識,請看
http://blog.kenyang.net/2011/03/java-staticfinal.html

1 public class MainFrame extends JFrame {
2 private JTextField textInput;
private JButton btnOK;

3 public MainFrame() {
4 textInput = new JTextField();
5 btnOK= JButton("");
6 btnOK.getModel();
7 btnOK.addActionListener(new ActionListener() {

8 public void actionPerformed(ActionEvent arg0) {
9 Searcher searcher = new Searcher();

10 if (arg0.getSource()==btnOK)
11 try {
12 searcher.search("contents", textInput.getText());
13 }
14 } catch (IOException | ParseException e) {
15 e.printStackTrace();
16 } } }); }
}


Read more...

2014年5月18日 星期日

心得筆記-java 的加強版 for 迴圈 (for each迴圈)

java 的 for 迴圈出現一種以前從沒有看過的格式。它是JAVA 5.0 後多的一種 for 迴圈寫法,目的是簡化陣列與集合物件的元素存取方式.
在JDK 5.0版新增加強型的for迴圈,其功能類似其他程式語言的foreach迴圈,可以輕鬆走訪陣列或集合物件的元素。

for-each 迴圈語法

for (型別 變數 : 集合或陣列物件參考或函式呼叫) {迴圈內程序}

冒號前面稱為宣告式, 後面稱為運算式. 宣告式的變數型別必須與陣列或集合的元素相容, 此變數將用在迴圈內部以便存取元素. 運算式可以是集合或陣列物件參考, 也可以是函式呼叫 (傳回陣列或集合).


舉例:

* for迴圈新舊寫法的對照
public class NewFor {
public static void main(String[] args) {

String [] a = {"1","3","5","7","9","11"};

//5.0前的for迴圈寫法
for(int i = 0 ; i < a.length ; i++){
String temp = a[i];
System.out.print(temp + ", ");
}

System.out.println();

//5.0後for迴圈也可以用這種新的寫法(for-each)
for(String temp : a){
System.out.print(temp + ", ");
}


* 用字串變數name配合加強型的for迴圈(for-each)來走訪names[]陣列

String[] names;
for ( String name: names )
{

System.out.print('\"'+name+"\"(字串長度:");
System.out.println(name.length() + ")");

}

可以看到程式碼比傳統用法更簡潔



* 用for 迴圈印出二維陣列之元素
int[][] a={{1,2},{3,4,5}, {6,7,8,9}};
for (int[] i : a) {
System.out.print(i.length);} //印出二維陣列的元素個數 2 3 4 (a[0]有二個元素{1,2}, a[1]有三個元素{3,4,5}, a[2]有四個元素{6,7,8,9})

for (int i : a[2]) {System.out.print(i);} //印出二維陣列第三個元素的內容6 7 8 9



* 以上範例均以陣列為例,如果用在集合物件的寫法
for (ScoreDoc scoreDoc : hits.scoreDocs) {
Document doc = searcher.doc(scoreDoc.doc);
System.out.println(doc.get("fullpath"));
}

這是我練習java時所寫的一個例中,hit.scoreDocs 為一集合物件,內含不定個數的物件,scoreDoc每次迴圈執行時,均會取得其中一個物件,for 迴圈遍歷結束後,便會把hit.scoreDocs內所有物件,指定給Document 型別的物件 doc , 並印出該文件的路徑。

如果用傳統寫法,應該是以下的樣子:
ScoreDoc scoreDoc;
for (int i=0;i<hits.scoreDocs.length;i++){
scoreDoc=hits.scoreDocs[i];
Document doc = searcher.doc(scoreDoc.doc);
System.out.println(doc.get("fullpath"));
}

參考:
http://tony1966.myweb.hinet.net/java/core/flow_control.htm

http://www.ibm.com/developerworks/library/j-forin/index.html


補充:
很多程式語言都有支援for-each這類的語法,簡單的說for-each語法就是當我們想要存取一個 Array 或 Collection 裡面所有的元時可以更方便、更有效率的語法。for-each 也有人稱為 enhanced for 或 for-in。

使用上要注意的事項有:

只適用於 Java 5.0 以後的版本
只適用於有 implement Iterable 的類別基本上 Array 與 Collection 類別都沒問題。
只能存取裡面元素而不能置換掉它,記住,for-each 裡面的變數是 local 變數離開 for-each 之後就會消失。
只能同時針對一個 Array 或 Collection 進行操作。
只能同時針對一個元素操作。
只能從頭開始訪問每個元素。

以上取自:
http://yindingtsai.blogspot.tw/2010/03/java-for-each-for-eachfor-each-array.html

Read more...

心得筆記- java 陣列的建立(固定,變動)

Java陣列的特性


Java的陣列並不以一塊連續的記憶體空間來表達,而是把陣列視為特殊的物件。此物件不但可存放資料,還利用該物件的length屬性記錄著該陣列的長度。


一維陣列的建立

int[] x;
x = new int[10]; // 必須利用new指令產生並定義該物件的空間
for (int i = 0; i < x.length; i++) { // 此物件有一個length屬性,用以紀錄該陣列的長度
x[i] = 10; //給定陣列的初值
}

多維陣列建立(二維陣列以上)


Java陣列物件是只能儲存基本資料型態或reference的一維陣列,二維以上的陣列是透過reference指到其他的一維陣列物件來達成。



二維陣列的建立 (第二維陣列的長度一致)
int[][] x;
x = new int[10][20]; //因陣列固定, 可以一次建立陣列物件
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x[i].length; j++) {
x[i][j] = 10; //定義初值
}


二維陣列的建立 (第二維陣列的長度不一致)
由於java以一維陣列來模擬二維陣列,因此透過第一個陣列的reference所找到的陣列,其長度不必然相同

int[][] x;
x = new int[10][]; // 因二維陣列不固定, 因此先產生10個第一維陣列
for (int i = 0; i < x.length; i++) {
x[i] = new int[i];
// 再分別產生i個第二維陣列, 因第一維陣列存放reference,可透過它指向另一個陣列,i值可以使用變數, 造成不固定長度。
}


不可使用未定義空間的陣列


Java在執行期間會對陣列的索引做檢查,如果超出來合法範圍,就會產生ArrayIndexOutOfBoundException的錯誤。

例如:
int[] x = new int[10]; //合法定義的空間為x[0] .. x[9]
x[10]=10; //超過範圍

就會產生ArrayIndexOutOfBoundException的錯誤訊息,並且終止該程式

java.lang.ArrayIndexOutOfBoundsException: 10
at ArrayExample4.main(ArrayExample4.java:5)
Exception in thread "main"

上面訊息的意義是:
java.lang.ArrayIndexOutOfBoundsException: 10告訴我們索引值是10的時候引起了此問題
at ArrayExample4.main(ArrayExample4.java:5)告訴我們呼叫ArrayExample4.main時在ArrayExample4.java的第五行產生錯誤

參考:
http://programming.im.ncnu.edu.tw/J_Chapter3.htm

Read more...

2014年5月16日 星期五

光陽機車偶而發不動問題記錄

這幾天買了四年多的光陽v1 125,開始出現一些毛病。原本很好啟動,現在有時候會啟動一兩次才能發動,有一次下雨天,到學校去載小孩,回程的時候,居然發動了四五次,好不容易才發動。

心想也許是電瓶老化了,用電表量一下電壓,12.8v。還很正常。但聽說車子不發動時,量到的只是表面電壓。我又量了一下發動時的瞬間電壓,大約10.1v到10.4v之間。有時候會降低到9.8v,但這都可以順利啟動。如果發不動時的瞬間電壓,往往只有5, 6v左右。

又有人說也許是電線接觸不良,我發現電池正極的地方卡了許多粉末,於是我拆開電線將之清除。再測試發動情況,發現瞬間啟動電壓已經提升到11v。心想也許是這個原因,可是還來不及高興太久,下一次的發動,還是不好發。

為了避免顧路的危險,還是決定買一顆電池來換。

新電池買來,前幾天還可以。但有一天突然又發不動了。這下子可以證明不是電池的問題了。而且原來那顆電池,電力應該也還夠。所以之前所說的表面電壓的說法,也許可信,但不全然是這一原因。像這種偶而發生發不動的狀況,應該是最難處理了。牽去機車行,也不一定查的出來。目前就且戰且走,待有一天完全發不動的時候再處理了。

Read more...

2014年5月11日 星期日

注電解液到機車電瓶經驗

從拍賣買了一顆機車電瓶。本來以為買來裝上去就好了。想不到還要自己diy,把電解液注液到電池裡。看外包裝的說明書,寫的有點複雜。其實說穿了就是把裝電池液的瓶子倒過來,對準電瓶的六個孔插進去,讓瓶子裡的電解液自動流到電瓶裡去。說來簡單,但做起來還是有一些地方要注意。

先撕開電瓶上紅色標籤。讓電瓶的注液孔露出來。
IMG_20140509_111847.jpg


先把白色瓶子上的黑色蓋子拆下來。先放到一旁,待會兒還會用到。
IMG_20140509_112036.jpg
IMG_20140509_112111.jpg

再將白色瓶子倒過來, 對準電瓶的六個孔垂直的插進去。這時白色瓶子六個瓶口的洞會被戳破,這個步驟需要用點力氣。

IMG_20140509_112239.jpg

插進去以後,讓白色瓶子裡的電解液自然流入電瓶內。這時後會看到白色瓶子裡會有氣泡冒出。說明書說這個狀態要維持二十分鐘以上。

IMG_20140509_112422.jpg

二十分鐘以後,用手拍拍白色瓶子上方,確保所有液體均已流入電瓶內。

取下白色瓶子,把剛才拆下的黑色蓋子蓋上電瓶上方的六個孔。要用力把它壓入,壓到底。

IMG_20140509_112730.jpg


這個步驟更需要力氣。小弟力氣實在不夠,只好借用工具。

IMG_20140509_112937.jpg


電瓶注液完成!新的電瓶量出來的電壓是13.14v。裝到機車,大功告成。

IMG_20140509_113133.jpg

Read more...

2014年5月6日 星期二

富士全錄FUJI XEROX P205B填充碳粉經驗談

今天使用印表機時,突然不能印了。一開機,沒出現慣有的機器熱機滾動的聲音,取而代之的是機器上的橘色燈閃了一下,然後熄滅。而慣常亮的綠燈倒是正常。

本來以為是這臺富士全錄FUJI XEROX P205B故障了。研究了一下,最後發現是沒碳粉了。還好當時買印表機時,另外向店家多買了兩盒碳粉。現在派上用場了。

可是怎麼安裝呢,其實也很簡單,只要取出碳粉匣,這臺p205b本身就有在碳粉匣上設計填充碳粉的洞。壓下碳粉匣上一個小凸起旁的卡榫,再撥開這個凸出部分,填充的洞就露出來了,直接把碳粉注入到洞裡面,再撥回凸出部分,裝回印表機。

但是怎麼還不能印呢?該不會是要更換原廠的碳粉匣,才能印吧!又上網作了一番功課,才發現必須執行全錄的一個印表機工具程式,並開啟"非原廠的功能。才能列印。

到富士全錄FUJI XEROX 下載工具程式(SimpleMonitor及印表機設定公用程式/快速啟用公用程式)
http://www.fujixerox.com.tw/downloads?product_id=81
操作步驟: 執行富士全錄的印表機設定公用程式->印表機維護->非全錄原裝碳粉模式->勾選啟動

雖然開啟這個功能,會出現什麼.....使用非原廠碳粉匣會喪失保固....等等字眼。但總得來說,全錄還算體貼我們這些窮客戶。也不需換晶片,只要打開印表機的工具軟體設定一下,一切又恢正常可以列印了。不像先前我使用hp噴墨印表機時,必須用美工刀把墨水夾切開,還要填充,弄的到處是墨水不說,也沒填進去多少。到最後還是非得買他們原廠的墨水匣。

youtube有教學
https://www.youtube.com/watch?v=V4bCdf7QP0s

不過這段影還有換晶片的動作,可能因為他買的是原廠的填充碳粉,我的是副廠的,直接如上述改設定就好了。

這裡有討論
http://www.mobile01.com/topicdetail.php?f=499&t=2560323

Read more...

  © Blogger templates Psi by Ourblogtemplates.com 2008

Back to TOP