代码之家  ›  专栏  ›  技术社区  ›  Alex Wayne

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

  •  9
  • Alex Wayne  · 技术社区  · 14 年前

    我怎样才能得到 userId

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

    我得到这个错误:

    无法在其他方法中定义的内部类中引用非最终变量userID

    我很确定我不能把它赋值为final,因为它是一个未知值的变量。我听说这种语法在某种程度上保留了作用域,所以我想一定有一种语法技巧我还不太清楚。

    5 回复  |  直到 14 年前
        1
  •  7
  •   Andrzej Doyle    14 年前

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

    我不知道你说它是一个未知值的变量是什么意思;最后的意思是,一旦给变量赋值,它就不能被修改 重新 -已分配。由于您没有在方法中更改userID的值,因此在本例中使其成为final是没有问题的。

        2
  •  10
  •   Community CDub    11 年前

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

    这就是为什么。。。如果您编写以下代码(长答案,但在底部,您可以得到短版本:-):

    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。通过要求局部变量是最终的,这种混乱的情况就不会出现。

        3
  •  2
  •   srk avivamg    3 年前

    最终有效 . 中的相关片段和示例 Oracle documentation

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

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

    例如,假设变量 numberLength 不是最终的,你 将突出显示的赋值语句添加到 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;
    }
    

    数不清的 不是 实际上是最后一次了。结果,Java编译器生成 类似于“从内部引用的局部变量”的错误消息 电话号码 变量:

    if (currentNumber.length() == numberLength)
    

    从JavaSE8开始,如果在方法中声明本地类,它 PhoneNumber本地类中的以下方法:

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

    printOriginalNumbers 访问参数 phoneNumber1 phoneNumber2 方法的定义 validatePhoneNumber

        4
  •  1
  •   doublep    14 年前

    做这个有什么问题吗 final

    public void doStuff (final String userID)
    
        5
  •  1
  •   mdma    14 年前

    声明方法

    public void doStuff(final String userID)
    

    值必须是final,这样编译器才能确保它不会更改。这意味着编译器可以随时将值绑定到内部类,而不必担心更新。

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