Java:使用局部变量的匿名内部类

如何在我的匿名内部子类中获取传递给此方法的userId的值?

 public void doStuff(String userID) { doOtherStuff(userID, new SuccessDelegate() { @Override public void onSuccess() { Log.e(TAG, "Called delegate!!!! "+ userID); } }); } 

我收到此错误:

不能在不同方法中定义的内部类中引用非最终变量userID

我很确定我不能将它指定为final,因为它是一个具有未知值的变量。 我听说这种语法确实以某种方式保留了范围,所以我认为必须有一个我还不太了解的语法技巧。

当然你可以将它指定为final – 只需将该关键字放在参数的声明中:

 public void doStuff(final String userID) { ... 

我不确定你的意思是它是一个具有未知值的变量; 所有这一切的最终手段是,一旦为变量赋值,就无法重新分配。 由于您没有在方法中更改userID的值,因此在这种情况下将其设置为final是没有问题的。

正如这里的其他人所说的那样,局部变量必须是内部类才能访问的最终变量。

这里(基本上)是为什么……如果你写下面的代码(长答案,但是,在底部,你可以得到短版本:-):

 class Main { private static interface Foo { void bar(); } public static void main(String[] args) { final int x; Foo foo; x = 42; foo = new Foo() { public void bar() { System.out.println(x); } }; foo.bar(); } } 

编译器大致翻译它:

 class Main { private static interface Foo { void bar(); } public static void main(String[] args) { final int x; Foo foo; x = 42; class $1 implements Foo { public void bar() { System.out.println(x); } } foo = new $1(); foo.bar(); } } 

然后这个:

 class Main { private static interface Foo { void bar(); } public static void main(String[] args) { final int x; Foo foo; x = 42; foo = new $1(x); foo.bar(); } private static class $1 implements Foo { private final int x; $1(int val) { x = val; } public void bar() { System.out.println(x); } } } 

最后到这个:

 class Main { public static void main(String[] args) { final int x; Main$Foo foo; x = 42; foo = new Main$1(x); foo.bar(); } } interface Main$Foo { void bar(); } class Main$1 implements Main$Foo { private final int x; Main$1(int val) { x = val; } public void bar() { System.out.println(x); } } 

重要的是它将构造函数添加到$ 1。 想象一下,如果你能做到这一点:

 class Main { private static interface Foo { void bar(); } public static void main(String[] args) { int x; Foo foo; x = 42; foo = new Foo() { public void bar() { System.out.println(x); } }; x = 1; foo.bar(); } } 

你会期望foo.bar()会打印出1但它实际上会打印出来。通过要求局部变量是最终的,这种混乱的情况不会出现。

让它成为final的问题是什么?

 public void doStuff (final String userID) 

声明方法

 public void doStuff(final String userID) 

该值必须是最终的,以便编译器可以确保它不会更改。 这意味着编译器可以随时将值绑定到内部类,而无需担心更新。

代码中的值不会发生变化,因此这是一个安全的更改。

在Java 8中,这已经发生了一些变化。 您现在可以访问有效的最终变量。 Oracle文档中的相关代码段和示例(强调我的):

但是,从Java SE 8开始,本地类可以访问最终或有效最终的封闭块的局部变量和参数。 在初始化之后其值永远不会改变的变量或参数实际上是最终的 。 例如,假设变量numberLength未声明为final,并在PhoneNumber构造函数中添加突出显示的赋值语句:

 PhoneNumber(String phoneNumber) { numberLength = 7; // From Kobit: this would be the highlighted line String currentNumber = phoneNumber.replaceAll( regularExpression, ""); if (currentNumber.length() == numberLength) formattedPhoneNumber = currentNumber; else formattedPhoneNumber = null; } 

由于这个赋值语句,变量numberLength不再是最终的。 因此,Java编译器生成类似于“从内部类引用的局部变量必须是final或者final final”的错误消息,其中内部类PhoneNumber尝试访问numberLength变量:

 if (currentNumber.length() == numberLength) 

从Java SE 8开始,如果在方法中声明本地类,它可以访问方法的参数。 例如,您可以在PhoneNumber本地类中定义以下方法:

 public void printOriginalNumbers() { System.out.println("Original numbers are " + phoneNumber1 + " and " + phoneNumber2); } 

printOriginalNumbers方法访问validatePhoneNumber方法的参数phoneNumber1phoneNumber2