编辑: 我需要改变几个变量的值,因为他们通过计时器运行几次。我需要在计时器的每次迭代中不断更新值。我不能将值设置为final,因为这将阻止我更新值,但是我得到了我在下面的初始问题中描述的错误:

我之前写过如下内容:

我得到错误“不能引用在不同方法中定义的内部类中的非最终变量”。 这发生在名为price的double和名为priceObject的price上。你知道我为什么会有这个问题吗?我不明白为什么我要做最后申报。如果你能看到我在做什么,我要怎么做才能解决这个问题。

public static void main(String args[]) {

    int period = 2000;
    int delay = 2000;

    double lastPrice = 0;
    Price priceObject = new Price();
    double price = 0;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);
}

当前回答

这是另一种解释。考虑下面这个例子

public class Outer{
     public static void main(String[] args){
         Outer o = new Outer();
         o.m1();        
         o=null;
     }
     public void m1(){
         //int x = 10;
         class Inner{
             Thread t = new Thread(new Runnable(){
                 public void run(){
                     for(int i=0;i<10;i++){
                         try{
                             Thread.sleep(2000);                            
                         }catch(InterruptedException e){
                             //handle InterruptedException e
                         }
                         System.out.println("Thread t running");                             
                     }
                 }
             });
         }
         new Inner().t.start();
         System.out.println("m1 Completes");
    }
}

这里的输出是

m1完成

线程运行

线程运行

线程运行

................

现在方法m1()完成,我们将引用变量o赋值为空,现在外部类对象有资格进行GC,但内部类对象仍然存在,与正在运行的线程对象有(has - a)关系。没有外部类对象,就不可能存在m1()方法,没有m1()方法,就不可能存在它的局部变量,但如果内部类对象使用m1()方法的局部变量,那么一切都是不言自明的。

为了解决这个问题,我们必须创建一个局部变量的副本,然后必须用内部类对象将其复制到堆中,java只对final变量做了什么,因为它们实际上不是变量,它们像常量(一切都发生在编译时,而不是在运行时)。

其他回答

为了解决上述问题,不同的语言做出了不同的决定。

对于Java,解决方案就像我们在本文中看到的那样。

对于c#,解决方案是允许副作用和引用捕获是唯一的选择。

对于c++ 11,解决方案是让程序员来做决定。他们可以选择通过值或引用来捕获。如果通过值捕获,则不会发生副作用,因为引用的变量实际上是不同的。如果通过引用捕获,可能会产生副作用,但程序员应该意识到这一点。

如果您想在匿名类中的方法调用中更改一个值,该“值”实际上是一个Future。所以,如果你用番石榴,你可以写

...
final SettableFuture<Integer> myvalue = SettableFuture<Integer>.create();
...
someclass.run(new Runnable(){

    public void run(){
        ...
        myvalue.set(value);
        ...
    }
 }

 return myvalue.get();

这是另一种解释。考虑下面这个例子

public class Outer{
     public static void main(String[] args){
         Outer o = new Outer();
         o.m1();        
         o=null;
     }
     public void m1(){
         //int x = 10;
         class Inner{
             Thread t = new Thread(new Runnable(){
                 public void run(){
                     for(int i=0;i<10;i++){
                         try{
                             Thread.sleep(2000);                            
                         }catch(InterruptedException e){
                             //handle InterruptedException e
                         }
                         System.out.println("Thread t running");                             
                     }
                 }
             });
         }
         new Inner().t.start();
         System.out.println("m1 Completes");
    }
}

这里的输出是

m1完成

线程运行

线程运行

线程运行

................

现在方法m1()完成,我们将引用变量o赋值为空,现在外部类对象有资格进行GC,但内部类对象仍然存在,与正在运行的线程对象有(has - a)关系。没有外部类对象,就不可能存在m1()方法,没有m1()方法,就不可能存在它的局部变量,但如果内部类对象使用m1()方法的局部变量,那么一切都是不言自明的。

为了解决这个问题,我们必须创建一个局部变量的副本,然后必须用内部类对象将其复制到堆中,java只对final变量做了什么,因为它们实际上不是变量,它们像常量(一切都发生在编译时,而不是在运行时)。

使用匿名类时,只能从包含类中访问最终变量。因此,您需要声明正在使用的变量为final(这对您来说不是一个选项,因为您正在更改lastPrice和price),或者不要使用匿名类。

因此,您的选择是创建一个实际的内部类,您可以在其中传递变量并以正常方式使用它们

or:

对于你的lastPrice和price变量,有一个快速(在我看来很难看)的方法,就是像这样声明它

final double lastPrice[1];
final double price[1];

在匿名类中,你可以这样设置值

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];

对我来说有用的是定义函数外面的变量。

就在主函数declare之前,即。

Double price;
public static void main(String []args(){
--------
--------
}