【问题标题】:Final passed as parameter [duplicate]最终作为参数传递[重复]
【发布时间】:2013-03-07 11:03:49
【问题描述】:

在以下示例中,它通过将参数int i 设置为final 来工作和编译

class Miner1
{
    Miner getMiner(final int i) {
        return new Miner() {                
           public void perform_work() { 
              System.out.println(i);
           }
        };
    }

interface Miner { void perform_work(); }

否则如果没有像前面的例子那样设置为final,它将无法编译。 有人知道为什么吗?即使没有final,它也应该在范围内,因为花括号尚未关闭。

提前致谢。

【问题讨论】:

  • 我打算回答这个问题,但上面的链接已经很好地涵盖了它:-) +1'd

标签: java parameters final


【解决方案1】:

这与作用域无关,而与anonymous inner classes 有关。

您不能从在父类中声明的匿名类访问局部变量,除非该变量是final

看看this 其他关于 SO 的问题,它解释了逻辑。

【讨论】:

    【解决方案2】:

    它与范围没有任何关系。

    在 Java 中,匿名类只能从 final 的外部范围引用那些变量。

    来自JLS

    任何使用但未在内部类中声明的局部变量、形参或异常参数都必须声明为final

    【讨论】:

    • @defaultlocale:谢谢先生。我一直在寻找那句话,但在错误的部分!
    【解决方案3】:

    Java 只允许从定义在方法/构造函数中的匿名类引用最终变量/参数。这是为了使代码的行为更直观。变量/参数的值在创建实例时通过隐藏的构造函数参数传递给匿名类的实例,因此匿名类的实例无法跟踪变量的进一步变化。如果允许访问非最终变量,则可以编写以下内容:

    int a = 5;
    
    Thread t = new Thread ()
    {
        @Override
        public void run ()
        {
            System.out.println (a); // This will print 5, rather than 6!
        }
    };
    
    a = 6;
    
    t.start ();
    

    并期望打印6。要理解为什么上面的代码会打印5,注意这段代码等价于以下:

    class MyThread extends Thread
    {
        int _a;
    
        public MyThread (int a)
        {
            this._a = a;
        }
    
        @Override
        public void run ()
        {
            System.out.println (_a);
        }
    }
    
    int a = 5;
    
    Thread t = new MyThread (a); // Value `5` is passed
    
    a = 6;
    
    t.start (); // Value `5` passed to the constructor earlier is printed here
    

    【讨论】:

    • 非常清楚,谢谢。
    【解决方案4】:

    这是因为,在 Java 中,匿名内部类只能访问 final 局部变量和类的字段。
    现在的问题是为什么?
    这是因为方法的局部变量(在您的情况下为getMiner)存在于堆栈中,并且仅在方法的生命周期内存在。局部变量的范围仅限于声明变量的封闭方法。当方法结束时,堆栈帧被吹走,变量是历史。但是即使在方法完成之后,在其中创建的内部类对象可能仍然在堆上存活。例如,如果通过getMiner 获得的匿名内部类Miner 的引用被传递到代码的其他位置并在那里使用,那么由于局部变量已经被炸毁,对于该对象来说将是一个奇怪的情况。此问题的一种解决方案可能是匿名内部类对象制作局部变量的副本。但同样不能保证匿名内部类对象会看到该变量的最新值,因为局部变量容易发生变化。

    但是如果局部变量是final的,它保证变量值在初始化后在任何情况下都不会改变,所以方法局部内部类可以只复制它以供私有使用,即使在之后仍然存在原始值已从堆栈中删除。

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 2014-04-22
      • 2013-08-13
      • 2020-12-20
      • 2011-04-30
      • 2018-02-07
      • 2021-09-24
      • 2019-07-23
      • 2011-04-07
      相关资源
      最近更新 更多