從一次意外開始說java匿名內部類

來源:互聯網
上載者:User

標籤:java   內部類   

java的內部類、匿名類本來以為自己用的已經很溜了, 結果, 就在昨天晚上12點來鐘發生了重大事故。要說事故的嚴重性呢,那就是導致我一晚上沒有睡著覺。

那下面先用一段類比代碼來描述下我出現的問題的:

public class Test {public static void main(String[] args) throws InterruptedException {View v = new View();v.show(1);Thread.sleep(500);v.mTextView.execute();Thread.sleep(1000);v.show(2);Thread.sleep(500);v.mTextView.execute();}}class View {public TextView mTextView;public void show(int position) {if(mTextView == null) {mTextView = new TextView();mTextView.setListener(new Listener() {@Overridepublic void click() {System.out.println("position = " + position);}});}mTextView.show();}}class TextView {private Listener mListener;public void setListener(Listener l) {mListener = l;}public void execute() {mListener.click();}public void show() {System.out.println("textview show...");}}interface Listener {public void click();}

不出意外的話, console肯定是列印的1  2, 但是偏偏就在這困擾到我了,列印的結果是1  1, 仔細順一下代碼,我們就應該去思考這個匿名內部類到底是怎麼使用的外部類那個方法的參數的。

從列印的結果上看, 我猜想肯定是在這個內部類的執行個體中儲存了position參數,那帶著這個猜想,我們來debug一下程式。


這是第一次執行到的時候, 發現什麼問題了嗎。 在mListener中竟然有一個和position相關的變數。到這裡,我們感覺那個猜測可能是正確的。再往下思考,既然在mListener對象中儲存了這個變數,那麼下次執行到,同一個對象,所以變數肯定是相同的,這樣也就解開我們的疑惑了。



總結一下:

在我們new一個匿名內部類的時候,如果使用了方法中的東西,那麼jvm會給我們的匿名類加一個構造方法,並且將這個參數傳遞進來,例如上面的例子中:

class View$Listener {public View$Listener(int position) {this.Listener$position = position;}public void click() {...}}

既然知道了這些,那麼我們的疑惑也就解開了, 那上面的問題怎麼解決呢? 其實我們很早之前就已經知道解決方案了,想想android中自訂Adapter的getView()方法,你會恍然大悟。上面的問題怎麼解決呢?就是把setListener放到if後面,而不是裡面。

public class Test {public static void main(String[] args) throws InterruptedException {View v = new View();v.show(1);Thread.sleep(500);v.mTextView.execute();Thread.sleep(1000);v.show(2);Thread.sleep(500);v.mTextView.execute();}}class View {public TextView mTextView;public void show(int position) {if(mTextView == null) {mTextView = new TextView();//mTextView.setListener(new Listener() {//@Override//public void click() {//System.out.println("position = " + position);//}//});}mTextView.setListener(new Listener() {@Overridepublic void click() {System.out.println("position = " + position);}});mTextView.show();}}class TextView {private Listener mListener;public void setListener(Listener l) {mListener = l;}public void execute() {mListener.click();}public void show() {System.out.println("textview show...");}}interface Listener {public void click();}

這樣在每次調用show方法時,都會重新new一個Listener內部類。


從一次意外開始說java匿名內部類

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.