如何将参数传递给匿名类?

时间:2011-02-24 16:04:07

标签: java anonymous-class

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

int myVariable = 1;

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

是否有任何方法可以让侦听器访问myVariable或传递myVariable而不将侦听器创建为实际的命名类?

11 个答案:

答案 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中添加的代码量+复杂性来重用某些东西比在很多时候复制和粘贴更糟糕。