153

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

int myVariable = 1;

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

侦听器有什么方法可以访问 myVariable 或传递 myVariable 而不将侦听器创建为实际的命名类?

4

12 回答 12

352

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

不需要“最终”声明。

于 2012-08-30T22:34:34.563 回答
81

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

但是,类可以引用包含范围的变量。对于匿名类,这些可以是包含类的实例变量或标记为 final 的局部变量。

编辑:正如彼得指出的那样,您还可以将参数传递给匿名类的超类的构造函数。

于 2011-02-24T16:08:22.947 回答
31

是的。您可以捕获对内部类可见的变量。唯一的限制是它必须是最终的

于 2011-02-24T16:05:44.807 回答
22

像这样:

final int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Now you can access it alright.
    }
});
于 2011-02-24T16:06:26.823 回答
14

这会变魔术

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));
于 2014-12-18T13:46:01.030 回答
8

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

看起来他们也在Why java Instance initializers中讨论过?以及实例初始化程序与构造函数有何不同?讨论与构造函数的区别。

于 2013-02-18T01:00:18.807 回答
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))

或者,使用 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);
于 2013-04-18T09:11:05.410 回答
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 在他的回答中没有做任何其他事情,而是使用了更多代码。

于 2013-10-30T16:40:48.090 回答
3

您可以使用普通 lambda(“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 是重构装饰器和适配器的好方法,请参见此处

我刚刚开始学习 lambdas,所以如果你发现错误,请随时写评论。

于 2017-03-14T21:46:25.897 回答
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

    });

 }
于 2014-07-03T22:41:07.530 回答
1

如果“myVariable”是一个字段,您可以使用一个合格的 this:

public class Foo {
    int myVariable = 1;

    new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            Foo.this.myVariable = 8;
        }
    });
}
于 2022-01-02T19:33:26.420 回答
-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 中添加大量代码+复杂性才能重用某些东西,这比仅仅复制和粘贴很多时间还要糟糕。

于 2014-09-09T14:06:31.583 回答