2011-02-24 42 views
124

是否可以傳遞參數或訪問外部參數到匿名類?例如:如何將參數傳遞給匿名類?

int myVariable = 1; 

myButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     // How would one access myVariable here? 
    } 
}); 

有什麼辦法使聽者無需創建聽者作爲實際命名的類訪問MYVARIABLE或傳遞MYVARIABLE?

+7

你可以從封閉方法引用'final'局部變量。 – 2011-02-24 16:05:47

+0

我的確喜歡Adam Mmlodzinski建議定義一個私有方法,該私有方法初始化私有myVariable實例,並且可以因爲返回'this'而在右括號處被調用。 – dlamblin 2013-02-21 04:22:41

+0

這個問題有一些共同的目標:http://stackoverflow.com/questions/362424/accessing-constructor-of-an-anonymous-class – 2013-04-18 09:20:41

回答

68

從技術上講,沒有,因爲匿名類不能有構造函數。

但是,類可以引用來自包含範圍的變量。對於匿名類,這些可以是來自包含類(es)的實例變量或標記爲最終的局部變量。

編輯:正如Peter指出的那樣,您還可以將參數傳遞給匿名類的超類的構造函數。

+19

一個匿名類使用它的父類的構造函數。例如'new ArrayList(10){}' – 2011-02-24 17:08:38

+0

好點。所以這將是將參數傳遞給匿名類的另一種方式,儘管很可能您無法控制該參數。 – 2011-02-24 17:50:15

+0

匿名類不需要構造函數 – newacct 2012-07-28 08:47:28

22

是的。你可以捕捉內部類可見的變量。唯一的限制是,它必須是最終

+0

從匿名類引用的實例變量不一定是final afaik。 – 2011-02-24 16:49:37

+8

實例變量通過最終的this來引用。 – 2011-02-24 17:04:27

+0

如果我不想將變量更改爲「final」,該怎麼辦?我找不到任何替代品。這可能會影響設計爲「最終」的原點參數。 – Stallman 2014-09-18 08:28:01

19

像這樣:

final int myVariable = 1; 

myButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     // Now you can access it alright. 
    } 
}); 
309

是的,通過添加一個初始化方法,返回「這個」,並立即調用該方法:

int myVariable = 1; 

myButton.addActionListener(new ActionListener() { 
    private int anonVar; 
    public void actionPerformed(ActionEvent e) { 
     // How would one access myVariable here? 
     // It's now here: 
     System.out.println("Initialized with value: " + anonVar); 
    } 
    private ActionListener init(int var){ 
     anonVar = var; 
     return this; 
    } 
}.init(myVariable) ); 

沒有「最終」需要申報。

+0

這真是太棒了!假設界面正在返回anonVar,但anonVar可能是一個集合,如果你可以將它設置爲final,那麼會很好,但是你會以另一種方式做到這一點。 – dlamblin 2013-02-21 04:20:38

+0

dlamblin,如果anonVar是一個集合,聲明它最終不會保護內容,如果你用getter方法暴露它。相反,您的getter方法需要返回Collection的副本,或者使用其中一個Collections.unmodifiableCollection()變體進行封裝。 如果您建議將其設置爲最終的,因爲您可能會對捕獲的構造函數參數進行最終確定,那麼,不,您不能這樣做 - 您需要改爲創建一個命名類。 – 2013-04-10 04:34:34

+4

哇...輝煌!我非常厭煩創建一個'final'引用對象,所以我可以將信息放入我的匿名類中。感謝你的分享! – 2013-04-17 21:30:04

8

http://www.coderanch.com/t/567294/java/java/declare-constructor-anonymous-class所示,您可以添加實例初始值設定項。這是一個沒有名字並且先被執行的塊(就像構造函數一樣)。

看起來他們也在Why java Instance initializers?How is an instance initializer different from a constructor?討論與構造函數的差異。

+0

這並不能解決被問到的問題。你仍然會遇到訪問局部變量的問題,所以你需要使用Adam Mlodzinski的解決方案或者 – 2013-04-17 22:21:24

+1

@MattKlein對我來說,它看起來像解決了它。實際上它是一樣的,不那麼冗長。 – haelix 2013-08-29 08:50:37

+1

這個問題想知道如何將參數傳遞到類中,就像使用需要參數的構造函數一樣。鏈接(應該在這裏總結)只顯示瞭如何使用無參數的實例初始值設定項,它不回答問題。這種技術可以與aav描述的'final'變量一起使用,但是這個答案沒有提供這個信息。到目前爲止,最好的答案是Adam Mlodzinksi給出的答案(我現在只使用這種模式,沒有更多的決賽!)。我支持我的評論,這並不回答問題。 – 2013-08-29 14:54:29

6

我的解決方案是使用返回實現的匿名類的方法。常規參數可以傳遞給方法,並且可以在匿名類中使用。

例如:(一些GWT代碼來處理一個文本框的變化):

textBox.addChangeHandler(newNameChangeHandler(myAxisName, myLogger)) 

/* Regular method. Returns the required interface/abstract/class 
    Arguments are defined as final */ 
private ChangeHandler newNameChangeHandler(final String axisId, final Logger logger) { 

    // Return a new anonymous class 
    return new ChangeHandler() { 
     public void onChange(ChangeEvent event) { 
      // Access method scope variables   
      logger.fine(axisId) 
     } 
    }; 
} 

在這個例子中,新的匿名類的方法將與參考OR,使用OP的要求:

private ActionListener newActionListener(final int aVariable) { 
    return new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      System.out.println("Your variable is: " + aVariable); 
     } 
    }; 
} 
... 
int myVariable = 1; 
newActionListener(myVariable); 
+0

這很好,它將匿名類限制爲幾個易於識別的變量,並且消除了必須使某些變量最終確定的可憎行爲。 – 2013-10-30 16:45:51

2

其他人已經回答說,匿名類只能訪問最終變量。但他們留下了如何保持原始變量不是最終的問題。 Adam Mlodzinski給出了一個解決方案,但是非常臃腫。這個問題有一個更簡單的解決方案:

如果你不想myVariable是最終的,你必須把它包裝在一個新的範圍內,它是無關緊要的,如果它是最終的。

int myVariable = 1; 

{ 
    final int anonVar = myVariable; 

    myButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      // How would one access myVariable here? 
      // Use anonVar instead of myVariable 
     } 
    }); 
} 

Adam Mlodzinski在他的回答中沒有做任何其他事情,但代碼更多。

+0

這仍然沒有額外的範圍。這與使用final的其他答案實際上是一樣的。 – 2013-10-31 00:34:29

+0

@AdamMlodzinski不,它與您的答案實際上是一樣的,因爲它引入了一個新的變量,其中原始變量的值在私人範圍內。 – ceving 2013-11-02 21:33:53

+0

它並不完全相同。在你的情況下,你的內部類不能修改anonVar - 因此,效果是不同的。 如果你的內部類必須維持某種狀態,你的代碼將不得不使用某種類型的對象來使用setter而不是基元。 – 2013-11-13 18:43:28

1

將一些值放入外部變量(不屬於匿名類) 的一種簡單方法是如何從屬!

以同樣的方式,如果你想得到一個外部變量的值,你可以創建一個方法,返回你想要的!

public class Example{ 

    private TypeParameter parameter; 

    private void setMethod(TypeParameter parameter){ 

     this.parameter = parameter; 

    } 

    //... 
    //into the anonymus class 
    new AnonymusClass(){ 

     final TypeParameter parameterFinal = something; 
     //you can call setMethod(TypeParameter parameter) here and pass the 
     //parameterFinal 
     setMethod(parameterFinal); 

     //now the variable out the class anonymus has the value of 
     //of parameterFinal 

    }); 

} 
-2

我以爲匿名類基本上是一樣的lambda但語法糟糕的......這原來是真實的,但語法還差和原因(應該是什麼)局部變量滲出到包含類。

您可以通過將它們放入父類的字段來訪問最終的變量。

接口:

public interface TextProcessor 
{ 
    public String Process(String text); 
} 

類:

private String _key; 

public String toJson() 
{ 
    TextProcessor textProcessor = new TextProcessor() { 
     @Override 
     public String Process(String text) 
     { 
      return _key + ":" + text; 
     } 
    }; 

    JSONTypeProcessor typeProcessor = new JSONTypeProcessor(textProcessor); 

    foreach(String key : keys) 
    { 
     _key = key; 

     typeProcessor.doStuffThatUsesLambda(); 
    } 

我不知道他們是否已經在Java 8整理了這一點(我被困在EE世界,而不是得到8)但在C#它看起來像這樣:

public string ToJson() 
    { 
     string key = null; 
     var typeProcessor = new JSONTypeProcessor(text => key + ":" + text); 

     foreach (var theKey in keys) 
     { 
      key = theKey; 

      typeProcessor.doStuffThatUsesLambda(); 
     } 
    } 

你不需要在c#中的獨立接口...我想念它!我發現自己在java中進行更糟糕的設計並重復自己,因爲在Java中添加重複使用某些代碼+複雜性比複製和粘貼大量時間要糟糕。

+0

看起來像另一個黑客,你可以使用的是有一個這裏提到的元素數組http://stackoverflow.com/a/4732586/962696 – 2014-09-09 14:08:14

11

這將做魔術

int myVariable = 1; 

myButton.addActionListener(new ActionListener() { 

    int myVariable; 

    public void actionPerformed(ActionEvent e) { 
     // myVariable ... 
    } 

    public ActionListener setParams(int myVariable) { 

     this.myVariable = myVariable; 

     return this; 
    } 
}.setParams(myVariable)); 
1

可以使用plain lambdas( 「lambda表達式可以捕捉變量」)

int myVariable = 1; 
ActionListener al = ae->System.out.println(myVariable); 
myButton.addActionListener(al); 

甚至功能

Function<Integer,ActionListener> printInt = 
    intvar -> ae -> System.out.println(intvar); 

int myVariable = 1; 
myButton.addActionListener(printInt.apply(myVariable)); 

使用功能是重構裝飾器和適配器的好方法,see here

我剛開始學習lambda,所以如果你發現一個錯誤,隨時寫評論。

相關問題