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
方法的参数phoneNumber1
和phoneNumber2