0

我有这个代码:

public void onPlayerInteract(PlayerInteractEvent event) {
    final Action action = event.getAction();
    Location l1 = null;
    Location l2 = null;
    if (action == Action.LEFT_CLICK_BLOCK){
        l1 = event.getClickedBlock().getLocation();
    } else if (action == Action.RIGHT_CLICK_BLOCK) {
        l2 = event.getClickedBlock().getLocation();
    }

    Thread t = new Thread() {
        @Override
        public void run() {
            while(true) {
                try {
                    Thread.sleep(1000*60*60);
                    Location maxx = l1.getX();
                    Location maxy = l1.getY();
                    Location maxz = l1.getZ();

                    Location minx = l2.getX();
                    Location miny = l2.getY();
                    Location minz = l2.getZ();

                    if(l1.getX() > l2.getX()){
                        //I can't execute this, errors!
                    }
                } catch (InterruptedException ie) {
                }
            }
        }
    };
    t.start();

它给了我错误,并说将 l1 和 l2 更改为决赛。如果我将 l1 和 l2 更改为决赛,它会给我另一个错误,它说 l1 = etc.,它说要删除决赛。

4

5 回答 5

7

l1并且l2是方法的局部变量onPlayerInteract()。在此方法中,您创建一个匿名内部类,它使用这些局部变量l1l2. 这只有在l1并且l2是最终的情况下才有可能。但是根据定义,最终变量只能分配一次,然后您分配 null,然后再分配另一个值。因此,您需要复制l1和复制l2最终变量,并在匿名类中使用这些最终副本:

public void onPlayerInteract(PlayerInteractEvent event) {
    final Action action = event.getAction();
    Location l1 = null;
    Location l2 = null;
    if (action == Action.LEFT_CLICK_BLOCK){
        l1 = event.getClickedBlock().getLocation();
    } else if (action == Action.RIGHT_CLICK_BLOCK) {
        l2 = event.getClickedBlock().getLocation();
    }

    final Location l1Final = l1;
    final Location l2Final = l2;

    Thread t = new Thread() {
        @Override
        public void run() {
            while(true) {
                try {
                    Thread.sleep(1000*60*60);
                    Location maxx = l1Final.getX();
                    Location maxy = l1Final.getY();
                    Location maxz = l1Final.getZ();

                    Location minx = l2Final.getX();
                    Location miny = l2Final.getY();
                    Location minz = l2Final.getZ();


                    if(l1Final.getX() > l2Final.getX()){
                        // ...
                    }
                } catch (InterruptedException ie) {
                }
            }
        }
    };
    ...
}
于 2012-05-25T22:46:00.430 回答
1
public void onPlayerInteract(PlayerInteractEvent event) {
    final Action action = event.getAction();
    final Location blockLocation = event.getClickedBlock().getLocation();
    final Location l1 = (action == Action.LEFT_CLICK_BLOCK) ? blockLocation : null;
    final Location l2 = (action == Action.RIGHT_CLICK_BLOCK) ? blockLocation : null;

    Thread t = new Thread() {
        ...
    }
}
于 2012-05-25T22:43:21.410 回答
1

您需要将 final 用于匿名内部类。如您所知,最终参考无法修改。

JB Nizet 的答案是正确的。

但请注意,不是 JB Nizet 代码:

Location l1 = null;
Location l2 = null;
if (action == Action.LEFT_CLICK_BLOCK){
    l1 = event.getClickedBlock().getLocation();
} else if (action == Action.RIGHT_CLICK_BLOCK) {
    l2 = event.getClickedBlock().getLocation();
}

final Location l1Final = l1;
final Location l2Final = l2;

您可以使用以下代码

final Location l1;
final Location l2;
if (action == Action.LEFT_CLICK_BLOCK){
    l1 = event.getClickedBlock().getLocation();
    l2 = null;
} else if (action == Action.RIGHT_CLICK_BLOCK) {
    l1 = null;
    l2 = event.getClickedBlock().getLocation();
} else {
    l1 = null;
    l2 = null;
}

由于局部变量永远不会被初始化(甚至为 null),编译器通常会告诉您在使用它之前对其进行初始化。但是如果你在 if/elseif/else 结构的所有情况下都初始化它,编译器肯定知道你在任何情况下都初始化了它。

无论如何,您的代码似乎没有任何意义,因为在任何情况下, l1 或 l2 都将为空。因此,您的线程将始终抛出 NullPointerException。


这里解释了为什么必须对匿名内部类使用 final: 为什么我们对匿名内部类使用 final 关键字?


另请注意,您不能使用语句 if(l1.getX() > l2.getX()){ 因为 getX() 和 getY() 返回 Location 并且无法使用 > 运算符进行比较。您应该考虑在 Location 类上使用 Comparable 然后执行 if ( l1.getX().compareTo(l2.getX()) > 0 ) { ... }

于 2012-05-25T23:18:44.370 回答
0

run 中的代码实际上是它自己的方法。您可以将其设为单独的可运行方法,并在实例化时将 y1 和 y2 传递给它,或者在运行中声明 y1 和 y2。

于 2012-05-25T22:50:23.420 回答
0

解决方案如@JB Nizet 所述,但如果变量具有设置方法,则无需复制变量。然后,您的代码将如下所示(还修复了 @ 解释的空指针:

public void onPlayerInteract(PlayerInteractEvent event) {
final Action action = event.getAction();
final Location l1 = new Location(); // Assumming Location has a default constructor.
final Location l2 = new Location();
if (action == Action.LEFT_CLICK_BLOCK){
    l1.setX(event.getClickedBlock().getLocation().getX());
    l1.setY(event.getClickedBlock().getLocation().getY());
} else if (action == Action.RIGHT_CLICK_BLOCK) {
    l2.setX(event.getClickedBlock().getLocation().getX());
    l2.setY(event.getClickedBlock().getLocation().getY());
}

Thread t = new Thread() {
    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000*60*60);
                Location maxx = l1Final.getX();
                Location maxy = l1Final.getY();
                Location maxz = l1Final.getZ();

                Location minx = l2Final.getX();
                Location miny = l2Final.getY();
                Location minz = l2Final.getZ();


                if(l1.getX() > l2.getX()){
                    // ...
                }
            } catch (InterruptedException ie) {
            }
        }
    }
};
...

}

@Kkkev asnwer 也应该可以正常工作,但要注意空指针。

于 2012-05-25T23:06:35.793 回答