启动一个新线程而不使变量最终化
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
要解决这个问题,您有一些可能性:
创建一个新的 final 变量,并在你的 Runnable 中使用它
final int finalPosition = 位置;
将它们放在一个数组中,并在您的 Runnable 中使用例如 params[0]。
我不喜欢这种方法
int[] params = new int[]{position, rowImpact, takenPawn};
为您的参数创建一个包装器对象
//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.
}
大家好,我想将以下代码放在不同于 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
要解决这个问题,您有一些可能性:
创建一个新的 final 变量,并在你的 Runnable 中使用它
final int finalPosition = 位置;
将它们放在一个数组中,并在您的 Runnable 中使用例如 params[0]。 我不喜欢这种方法
int[] params = new int[]{position, rowImpact, takenPawn};
为您的参数创建一个包装器对象
//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.
}