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

发布于 2024-09-09 08:07:53 字数 456 浏览 2 评论 0原文

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

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

我收到此错误:

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

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

How can I get the value of userId passed to this method in my anonymous inner subclass here?

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

I get this error:

Cannot refer to a non-final variable userID inside an inner class defined in a different method

I'm pretty sure I can't assign it as final since it's a variable with an unknown value. I had heard that this syntax does preserve scope in some way, so I think there must be a syntax trick I don't quite know yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

请恋爱 2024-09-16 08:07:53

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

这(基本上)是为什么......如果您编写以下代码(很长的答案,但是在底部,您可以获得简短的版本:-):

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,但实际上会打印出 42。通过要求局部变量为最终变量,就不会出现这种令人困惑的情况。

As everyone else here has said, local variables have to be final to be accessed by an inner class.

Here is (basically) why that is... if you write the following code (long answer, but, at the bottom, you can get the short version :-):

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();
    }
}

the compiler translates it roughly like this:

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();
    }
}

and then this:

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);
        }
    }
}

and finally to this:

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);
    }
}

The important one is where it adds the constructor to $1. Imagine if you could do this:

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();
    }
}

You would expect that foo.bar() would print out 1 but it would actually print out 42. By requiring local variables to be final this confusing situation cannot arise.

久而酒知 2024-09-16 08:07:53

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

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

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

Sure you can assign it as final - just put that keyword in the declaration of the parameter:

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

I'm not sure what you meant about it being a variable with an unknown value; all that final means is that once a value is assigned to the variable, it cannot be re-assigned. Since you're not changing the value of the userID within your method, there's no problem making it final in this case.

累赘 2024-09-16 08:07:53

在 Java 8 中,这种情况发生了一些变化。您现在可以访问实际上是最终的变量。相关片段和示例来自 Oracle 文档(强调我的):

但是,从 Java SE 8 开始,本地类可以访问本地
封闭块的变量和参数是最终的或
有效最终

有效最终: 非最终变量或参数,其值在初始化后从未改变,因此实际上是最终的

例如,假设变量 numberLength 未声明为 Final,并且您
PhoneNumber 中添加突出显示的赋值语句
构造函数:

电话号码(字符串电话号码){
    数字长度 = 7; // 来自 Kobit:这将是突出显示的行
    字符串 currentNumber = 电话号码.replaceAll(
        正则表达式, "");
    if (currentNumber.length() == numberLength)
        格式化电话号码 = 当前号码;
    别的
        格式化电话号码 = null;
}

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

if (currentNumber.length() == numberLength)

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

public void printOriginalNumbers() {
    System.out.println("原号码为 " + PhoneNumber1 +
        " 和 " + 电话号码2);
}

方法printOriginalNumbers访问参数
validatePhoneNumber

方法的 phoneNumber1phoneNumber2

In Java 8, this has changed a little bit. You can now access variables that are effectively final. Relevant snippet and example from the Oracle documentation (emphasis mine):

However, starting in Java SE 8, a local class can access local
variables and parameters of the enclosing block that are final or
effectively final.

Effectively final: A non-final variable or parameter whose value is never changed after it is initialized is effectively final.

For example, suppose that the variable numberLength is not declared final, and you
add the highlighted assignment statement in the PhoneNumber
constructor:

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;
}

Because of this assignment statement, the variable numberLength is not
effectively final anymore. As a result, the Java compiler generates an
error message similar to "local variables referenced from an inner
class must be final or effectively final" where the inner class
PhoneNumber tries to access the numberLength variable:

if (currentNumber.length() == numberLength)

Starting in Java SE 8, if you declare the local class in a method, it
can access the method's parameters. For example, you can define the
following method in the PhoneNumber local class:

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

The method printOriginalNumbers accesses the parameters
phoneNumber1 and phoneNumber2 of the method validatePhoneNumber

夜灵血窟げ 2024-09-16 08:07:53

将其设为final 有什么问题吗?

public void doStuff (final String userID)

What's the problem with making it final as in

public void doStuff (final String userID)
伴随着你 2024-09-16 08:07:53

声明方法

public void doStuff(final String userID)

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

该值在您的代码中没有更改,因此这是一个安全的更改。

declare the method

public void doStuff(final String userID)

The value needs to be final so that the compiler can be sure it doesn't change. This means the compiler can bind the value to the inner class at any time, without worrying about updates.

The value isn't changing in your code so this is a safe change.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文