Java - 在匿名方法

时间:2015-08-10 14:19:20

标签: java anonymous

今天我遇到了这个问题,我无法理解正在发生的事情。

目的是创建一个可以更改参数对象的匿名方法。我虽然想出了一种智能的方法来传递值并在不同对象之间修改它们而没有对另一个对象的明确知识,但是有些事情是错误的。 以下代码概述了一般问题:

void foo() {
    String a = "foo";

    MethodMap.addMethod("1", new Method() {
        @Override
        public void execute(Object ... args) {
             args[0] = "bar";
        }
    } );
    MethodMap.invoke("1", a);
    System.out.println(a);
}

class MethodMap {
    private static Map<String, Invocation> map = new HashMap<>();

    public static boolean addMethod(String key, Invocation method) {
        map.put(key, method);
    }

    public static void invoke(String key, Object ... args){
        map.get(key).execute(args);
    }
}

public interface Invocation {
    public void execute(Object ... args);
}

我的意图是此代码应输出 bar ,但它会输出 foo 。我不太清楚为什么会这样。是不是通过引用传递了Java对象?在那种情况下,我不能修改它们吗?

有人可以解释一下我错过了什么吗?

我对该领域术语的了解可能实际上限制了我在网上搜索此内容的能力,因为我不知道谷歌会说些什么。

谢谢// Simon

2 个答案:

答案 0 :(得分:5)

Java始终是按值传递的。除了在声明它的方法中重新分配局部变量之外,您根本无法更改局部变量指向的内容。与其他一些语言不同,您不能通过引用传递a“并使用另一种方法更新它所指向的内容。

通过指定arg[0] = "bar",您可以成功将值"bar"分配给参数数组的第一个元素。但这对a没有影响。

见:

答案 1 :(得分:1)

args[]是匿名MethodMap实例中的局部变量,它引用一个临时数组,该数组是为了保存.invoke(...)调用的额外参数而隐式创建的。

分配args[0]时所做的就是更新临时数组。

void foo() {
    // a is a local variable in your foo() method that refers to an
    // immutable String object with the value, "foo".
    String a = "foo";

    MethodMap.addMethod("1", new Method() {
        @Override

        // args is a local variable in the execute() method, that refers
        // to a temporary Array object. 
        public void execute(Object ... args) {

             // This assignment changes the zeroth element of the temporary
             // array to point to a String object with the value, "bar".
             args[0] = "bar";
        }
    } );

    // The compiler turns your MethodMap.invoke() call into this:
    //       Array<Object> tmp = new Array<Object>[1];
    //       tmp[0] = a;   // tmp[0] now refers to the same immutable String as a.
    //       MethodMap.invoke("1", tmp);
    // The tmp array is ignored after the invoke call returns.
    MethodMap.invoke("1", a);

    System.out.println(a);
}