Привет, ребята, я хочу разместить следующий код в новом потоке, который отличается от потока пользовательского интерфейса, но студия Android выдает ошибку о том, что переменная должна быть объявлена ​​окончательной. когда я объявляю переменную 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);
            }
        }
    }

Я пытаюсь достичь чего-то подобного, не делая мою переменную final

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

    }
0
Franklyn Oreben 17 Сен 2021 в 11:51

2 ответа

Лучший ответ

Код, который вы здесь показали, не требует final, по крайней мере, при компиляции в Java 8 +, что позволяет анонимным классам ссылаться на эффективные конечные переменные.

Единственная причина, по которой вы не сможете ссылаться на параметры внутри анонимного класса, - это наличие кода, который их переназначает (внутри или вне анонимного класса): без переназначения параметры будут считаться фактически окончательными .

Если в этом методе есть другой код, который переназначает эти переменные, простой ответ - извлечь либо код, который вы показали, либо код, который вы не сделали, в другой метод:

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.

Или вы можете объявить Runnable с именованным классом и дать ему конструктор и явные поля:

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

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

  // run() method.
}
1
Andy Turner 17 Сен 2021 в 09:51

Вы не должны делать position, rowImpact или takePawn final. Но вы не можете изменить его до создания нового потока (new Runnable () .. Если вам нужно, чтобы это было окончательно ... почему? вот подробное описание: https: // blog.brendanlacanette.com/2015/08/variable-is-accessed-within-inner-class.html

Чтобы решить эту проблему, у вас есть несколько возможностей:

  1. создайте новую конечную переменную и используйте ее в своем Runnable

    final int finalPosition = позиция;

  2. поместите их в массив и используйте, например, params [0] в вашем Runnable. Мне не нравится такой подход

    int [] params = new int [] {позиция, rowImpact, takePawn};

  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 
0
Andreas Radauer 17 Сен 2021 в 09:46