2011-02-24 85 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,所以如果你发现一个错误,随时写评论。

相关问题