启动一个新线程而不使变量最终化

Start a new thread without making variables final

大家好,我想将以下代码放在不同于 ui 线程的新线程中,但是 android studio 给出了一个错误,该变量需要声明为 final。当我声明变量 final 时,它使我的应用程序崩溃。请问如何在不声明变量final的情况下启动一个新线程。

public void checkUpTaking(int position, int rowImpact, int takenPawn) { //taken pawn: -1 = brown, 1 = white
        if (position > 10) { //if you'll try to take from the last row - array out of bounds
            if (position % 5 != 0 && playableTile[position - 1 - 4 - rowImpact].getIsTaken() == takenPawn &&
                    playableTile[position - 1 - 9].getIsTaken() == 0) {
                checkTreeNodes(position, position - 9, position-4-rowImpact); //checking possible mandatory moves before clicking pawn
            }
            if ((position - 1) % 5 != 0 && playableTile[position - 1 - 5 - rowImpact].getIsTaken() == takenPawn &&
                    playableTile[position - 1 - 11].getIsTaken() == 0) {
                checkTreeNodes(position, position - 11, position-5-rowImpact);
            }
        }
    }

我试图在不使我的变量成为最终变量的情况下实现这样的目标

  public void checkUpTaking(int position, int rowImpact, int takenPawn) { //taken pawn: -1 = brown, 1 = white
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (position > 10) { //if you'll try to take from the last row - array out of bounds
                    if (position % 5 != 0 && playableTile[position - 1 - 4 - rowImpact].getIsTaken() == takenPawn &&
                            playableTile[position - 1 - 9].getIsTaken() == 0) {
                        checkTreeNodes(position, position - 9, position-4-rowImpact); //checking possible mandatory moves before clicking pawn
                    }
                    if ((position - 1) % 5 != 0 && playableTile[position - 1 - 5 - rowImpact].getIsTaken() == takenPawn &&
                            playableTile[position - 1 - 11].getIsTaken() == 0) {
                        checkTreeNodes(position, position - 11, position-5-rowImpact);
                    }
                }
            }
        }).start();

    }

您不必将 position、rowImpact 或 takenPawn 设为最终。 但是你不能在你的 new Thread(new Runnable().. 如果你必须它必须是最终的..为什么?这里有一个详细的描述:https://blog.brendanlacanette.com/2015/08/variable-is-accessed-within-inner-class.html

要解决这个问题,您有一些可能性:

  1. 创建一个新的 final 变量,并在你的 Runnable 中使用它

    final int finalPosition = 位置;

  2. 将它们放在一个数组中,并在您的 Runnable 中使用例如 params[0]。 我不喜欢这种方法

    int[] params = new int[]{position, rowImpact, takenPawn};

  3. 为您的参数创建一个包装器对象

    //as own class or even as inner class
    public class CheckupParameters
    {
        public CheckupParameters(int position, int rowImpact, int takenPawn)
        {
            this.position = position;
            this.rowImpact = rowImpact;
            this.takenPawn = takenPawn;
        }
        
        int position;
        int rowImpact;
        int takenPawn;
    }
    
    // in then before your Thread...
    CheckupParameters checkupParameters = new CheckupParameters(position, rowImpact,     takenPawn);
    
    // and in your Runnable you can access
    params.position 

您在此处显示的代码 doesn't require final,至少在 Java 8+ 中编译时是这样,它允许匿名 classes 引用有效最终变量。

您无法在匿名 class 中引用参数的唯一原因是是否存在重新分配它们的代码(在匿名 class 内部或外部):没有重新分配, 参数将被视为 effectively final.

如果此方法中有其他代码重新分配这些变量,简单的答案是将您显示的代码或未显示的代码提取到另一个方法中:

public void checkUpTaking(int position, int rowImpact, int takenPawn) {
  // The code creating the thread.

  restOfTheMethodBody(position, rowImpact, takenPawn);
}

private void restOfTheMethodBody(int position, int rowImpact, int takenPawn) {
  // The code which needs to update position/rowImpact/takenPawn.
}

或者您可以声明与参数具有相同值的额外变量,并在线程内引用它们:

int positionCopy = position;
// etc.

或者您可以使用命名的 class 声明 Runnable,并为其提供构造函数和显式字段:

class CheckUpTakingRunnable implements Runnable {
  private final int position;
  // etc.

  CheckUpTakingRunnable(int position /* etc */) {
    this.position = position;
  }

  // run() method.
}