是否可以传递参数或访问外部参数到匿名类?例如:
int myVariable = 1;
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// How would one access myVariable here?
}
});
是否有任何方法可以让侦听器访问myVariable或传递myVariable而不将侦听器创建为实际的命名类?
答案 0 :(得分:326)
是的,通过添加一个返回'this'的初始化方法,并立即调用该方法:
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) );
不需要'最终'声明。
答案 1 :(得分:73)
从技术上讲,不,因为匿名类不能有构造函数。
但是,类可以引用包含范围的变量。对于匿名类,这些可以是包含类的实例变量或标记为final的局部变量。
编辑:正如Peter指出的那样,您还可以将参数传递给匿名类的超类的构造函数。
答案 2 :(得分:27)
是肯定的。你可以捕获变量,对内部类可见。唯一的限制是它必须是最终
答案 3 :(得分:20)
像这样:
final int myVariable = 1;
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Now you can access it alright.
}
});
答案 4 :(得分:13)
这将做魔术
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));
答案 5 :(得分: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?讨论了与构造函数的差异。
答案 6 :(得分:7)
我的解决方案是使用一个返回已实现的匿名类的方法。常规参数可以传递给方法,并且可以在匿名类中使用。
例如:(从某些GWT代码处理文本框更改):
/* 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)
}
};
}
对于此示例,新的匿名类方法将引用:
textBox.addChangeHandler(newNameChangeHandler(myAxisName, myLogger))
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);
答案 7 :(得分:3)
其他人已经回答说匿名类只能访问最终变量。但他们留下了如何保持原始变量非最终的问题。 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在他的回答中没有做任何其他事情,但有更多的代码。
答案 8 :(得分:3)
您可以使用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) );
使用Function是重构装饰器和适配器的好方法,see here
我刚开始学习lambdas,所以如果发现错误,请随时写评论。
答案 9 :(得分:1)
将一些值放入外部变量的简单方法(不属于anonymus类)
是怎么回事!
以同样的方式,如果你想获得外部变量的值,你可以创建一个返回你想要的方法!
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
});
}
答案 10 :(得分:-2)
我认为匿名类基本上就像lambdas但语法更差......结果证明这是真的,但语法更糟,导致(应该是)本地变量渗透到包含类中。
您可以通过将它们放入父类的字段来访问任何最终变量。
例如
接口:
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中添加的代码量+复杂性来重用某些东西比在很多时候复制和粘贴更糟糕。