【问题标题】:Local variable defined in an enclosing scope must be final or effectively final在封闭范围内定义的局部变量必须是最终的或有效的最终
【发布时间】:2017-08-28 21:04:22
【问题描述】:

我正在尝试打印出x/mol 的百分比,但我似乎无法让它工作。我收到此错误:Local variable x defined in an enclosing scope must be final or effectively final

它说这发生在第 22 行,并且没有简单的解决方法。 java 的作用域是什么,如何将 x 添加到作用域中以便我的计时器可以读取它。

import java.math.BigInteger;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;

public class mol {
    public static void main(String[] args) {

        String writable = "";
        BigInteger x = new BigInteger("0");
        BigInteger mol = new BigInteger("602214179000000000000000");
        File file = new File("molA.txt");
        BufferedWriter bw = null;
        FileWriter fw = null;
        Timer t;
        t = new Timer(10000, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(x.divide(mol) + "%");
                System.out.println(x);
            }
        });

        System.out.println("Starting...");
        t.start();


        do {
             writable += "a";
            x = x.add(new BigInteger("1"));
        } while (x.compareTo(mol) < 0);

        try {

            fw = new FileWriter(file);
            bw = new BufferedWriter(fw);
            bw.write(writable);

            System.out.println("Done");

        } catch (IOException e) {

            System.out.println(e);

        } finally {

            try {

                if (bw != null)
                    bw.close();

                if (fw != null)
                    fw.close();

            } catch (IOException ex) {

                System.out.println(ex);

            }
        }
        t.stop();
        System.out.println("Finished!");

    }
}

【问题讨论】:

  • "它说这发生在第 22 行" 我们没有行号,所以请指出是哪一行代码。
  • @takendarkk 错误来自前两行System.out.println
  • 让 OP 真正更新他们的问题。如果我真的需要知道行号是什么,我可以复制/粘贴到记事本++。
  • @Harald 它不是重复的,因为在这种情况下,OP *wants 能够重新分配x,因此它不能被声明为final

标签: java


【解决方案1】:

您不能在嵌套类中使用局部变量,因为 JVM 要求它是 final 或至少“有效地最终”(这意味着 x 的值不能在以后修改)。

您可以通过在 main 之外将 x 声明为静态变量来绕过它:

static volatile BigInteger x = new BigInteger("0");
public static void main(String[] args) {
....

注意它也被声明为volatile,因为主线程修改了它,并且您希望 Timer 看到 x 的更新值(如果您不将其声明为 volatile,Timer 可能会看到陈旧的值)。

【讨论】:

  • 当然,如果mol有多个实例,这就会成为问题。我更喜欢让它成为一个实例变量并在main 中实例化一个mol,将main 的胆量拉到另一个方法中。
  • @StephenP 如果需要 mol 的多个实例,这确实是一个很好的解决方法,而且通常也是一个很好的做法(不要在 main 中做所有事情)。
【解决方案2】:

为了在嵌套类中使用方法的局部变量,该变量必须要么是final要么是“有效最终”,后者意味着编译器可以证明变量的值在执行期间不会改变方法的整个执行。如果不满足该条件,则嵌套类使用变量的语义将不清楚——将使用变量的多个值中的哪一个,在什么时候?

有几种方法可以解决这个问题:

  1. 对于您的特定目的,您似乎应该将x 声明为类变量而不是局部变量。 (它不能是实例变量,因为您是从静态上下文中访问它。)但是,您可以选择

  2. 使x 最终或有效最终。例如,将对x 的引用复制到final 变量,并让您的ActionListener 访问该副本,而不是访问x

  3. 或者您可以创建并实例化一个命名的ActionListener 实现类,嵌套的或顶级的,使用可以传递x 的构造函数。然后,该实现可以使用初始化它的引用来访问x 所引用的对象,但由于BigIntegers 是不可变的,它无法修改该对象。

【讨论】:

  • 解决方案 #2 和 #3 在这种情况下并不好,因为 OP 显然希望能够重新分配 x 并让 Timer 了解新值。跨度>
  • 嗯,是的,@alfasin,这就是为什么我说#1 似乎是 OP 应该做的。其他替代方案主要是为了更好地了解一般问题。
【解决方案3】:

创建一个类来保存 BigDecimals

public class MyContainer {
    private BigDecimal x = null;

    public MyContainer(BigDecimal x) {
        this.x = x;
    }

    public BigDecimal getX() {
        return x;
    }

    public void setX(BigDecimal x) {
        this.x = x;
    }
}

然后在第 14 行左右的代码中。

final MyContainer myContainer = new MyContainer(new BigDecimal(0));

然后在你的计时器中,

System.out.println(myContainer.getX().divide(mol) + "%");

【讨论】:

    【解决方案4】:

    使用委托模式

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.math.BigInteger;
    
    import javax.swing.Timer;
    
    public class BigDecimalTest {
        public static void main(String[] args) {
            StringBuffer writable = new StringBuffer;
            final MyBigInteger x = new MyBigInteger("0");
            BigInteger mol = new BigInteger("602214179000000000000000");
            Timer t;
            t = new Timer(10000, new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println(x.divide(mol) + "%");
                    System.out.println(x);
                }
            });
    
            System.out.println("Starting...");
            t.start();
    
            do {
                 writable.append("a");
                 x.add(new BigInteger("1"));
            } while (x.compareTo(mol) < 0);
    
            File file = new File("molA.txt");
            try (
                    FileWriter fw = new FileWriter(file);
                    BufferedWriter bw = new BufferedWriter(fw);
                    ) {
                bw.write(writable.toString());
                System.out.println("Done");
            } catch (IOException e) {
                System.out.println(e);
            }
            t.stop();
            System.out.println("Finished!");
        }
    }
    
    
    import java.math.BigInteger;
    import java.util.Random;
    
    public class MyBigInteger extends BigInteger {
        private static final long serialVersionUID = 1L;
    
        private BigInteger delegate = null;
    
        public MyBigInteger(byte[] arg0) {
            super(arg0);
            delegate = new BigInteger(arg0);
        }
    
        public MyBigInteger(String arg0) {
            super(arg0);
            delegate = new BigInteger(arg0);
        }
    
        public MyBigInteger(int arg0, byte[] arg1) {
            super(arg0, arg1);
            delegate = new BigInteger(arg0, arg1);
        }
    
        public MyBigInteger(String arg0, int arg1) {
            super(arg0, arg1);
            delegate = new BigInteger(arg0, arg1);
        }
    
        public MyBigInteger(int arg0, Random arg1) {
            super(arg0, arg1);
            delegate = new BigInteger(arg0, arg1);
        }
    
        public MyBigInteger(int bitLength, int certainty, Random rnd) {
            super(bitLength, certainty, rnd);
            delegate = new BigInteger(bitLength, certainty, rnd);
        }
    
        @Override
        public MyBigInteger divide(BigInteger divisor) {
            delegate = delegate.divide(divisor);
            return this;
        }
    
        @Override
        public MyBigInteger add(BigInteger addition) {
            delegate = delegate.add(addition);
            return this;
        }
    
        @Override
        public String toString() {
            return delegate.toString();
        }
    
        @Override
        public int compareTo(BigInteger compare) {
            return delegate.compareTo(compare);
        }
    }
    

    我担心您正在尝试将 510Zb(510 Zetta 字节)写入文件,或者甚至尝试创建这么长的字符串。我猜你的系统会崩溃,因为你没有足够的内存来保存字符串,并且你没有足够的磁盘空间来存储交换文件或写入 molA.txt 文件。如果它确实有效,它可能需要很长时间才能运行。

    【讨论】:

      猜你喜欢
      • 2019-10-28
      • 1970-01-01
      • 2019-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-27
      相关资源
      最近更新 更多