如何向匿名类传递参数?

是否可以向匿名类传递参数或访问外部参数? 例如:

int myVariable = 1;


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

有没有什么方法可以让侦听器访问或者传递 myVariable,而不需要将侦听器创建为一个实际的命名类?

98343 次浏览

是的。你可以捕获变量,可见的内部类。唯一的限制是,它必须是 期末考试

像这样:

final int myVariable = 1;


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

从技术上讲,没有,因为匿名类不能有构造函数。

但是,类可以从包含范围引用变量。对于匿名类,这些变量可以是来自包含类(es)的实例变量,也可以是标记为 final 的局部变量。

Edit : 正如 Peter 指出的,您还可以将参数传递给匿名类的超类的构造函数。

是的,通过添加返回“ 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)  );

不需要“最终”声明。

http://www.coderanch.com/t/567294/java/java/declare-constructor-anonymous-class所示,您可以添加一个实例初始值设定项。它是一个没有名称且首先执行的块(就像构造函数一样)。

为什么是 java 实例初始化器?实例初始值设定项与构造函数有什么不同?中似乎也讨论了它们与构造函数的区别。

我的解决方案是使用一个返回实现的匿名类的方法。正则参数可以传递给方法,并且在匿名类中可用。

例如: (从一些 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)
}
};
}

对于此示例,新的匿名 class-method 将通过以下方式引用:

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);

其他人已经回答说,匿名类只能访问 final 变量。但他们留下的问题是,如何保持原来的变量非最终。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 在他的回答中没有做任何其他事情,而是使用了更多的代码。

一个简单的方法来赋予外部变量一些价值(不属于匿名类) 是如何跟随!

同样的,如果你想得到一个外部变量的值,你可以创建一个方法来返回你想要的!

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


});


}

我认为匿名类基本上和 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 中重复使用某些东西所需要添加的代码 + 复杂性的数量比大量的复制和粘贴更糟糕。

这个会有奇效的

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));

您可以使用 普通的羊羔(“ 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) );

使用函数是重构修饰符和适配器 看这里的一种很好的方法

我刚开始学 Lambdas,所以如果你发现了错误,随时可以写评论。

如果“ myVariable”是一个字段,则可以使用限定的 this:

public class Foo {
int myVariable = 1;


new ActionListener() {
public void actionPerformed(ActionEvent e) {
Foo.this.myVariable = 8;
}
});
}