Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 作为参数传递的Final_Java_Parameters_Final - Fatal编程技术网

Java 作为参数传递的Final

Java 作为参数传递的Final,java,parameters,final,Java,Parameters,Final,在下面的示例中,它通过将参数int i设置为final class Miner1 { Miner getMiner(final int i) { return new Miner() { public void perform_work() { System.out.println(i); } }; } interface Miner { v

在下面的示例中,它通过将参数
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
,它也应该在范围内,因为大括号尚未闭合


提前感谢。

这与范围无关

在Java中,匿名类只能引用那些来自外部作用域的变量,这些变量是
final

从:

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


这与范围无关,而是与范围有关

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


看看上面的其他问题,这就解释了逻辑。

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 ();
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
并希望打印
6
。要理解为什么上面的代码会打印
5
,请注意此代码等同于以下代码:

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

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

但是如果局部变量是final,它确保了变量值在初始化后在任何情况下都不会改变,因此,方法local internal class只需将其复制一份供私人使用,即使原始值已从堆栈中删除,它仍将存在。

我本打算回答这个问题,但上面的链接已经很好地涵盖了它:-)+1'd+1@defaultlocale:谢谢您,先生。我一直在寻找那句话,但在错误的部分!非常清楚,谢谢。