【问题标题】:I need to make variable be used outside of the if statement. It says I need to make if final, but If I try using it it won't work我需要在 if 语句之外使用变量。它说我需要制作 if final,但如果我尝试使用它,它将无法正常工作
【发布时间】:2012-05-25 22:36:17
【问题描述】:

我有这个代码:

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 更改为 final,它会给我另一个错误,它说 l1 = etc.,它说要删除 final。

【问题讨论】:

  • 如果一个变量是最终的,你不能重新分配它。你需要重新设计你的设计。
  • 您还有另一个问题:l1 或 l2(或两者!)都将为 null,但您在取消引用之前没有检查 null。
  • 另一个问题是他试图将 SO 用作教科书。只需阅读有关线程、Runnables、类、变量等的信息……然后重新实现您的解决方案。

标签: java variables global-variables


【解决方案1】:

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

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) {
                }
            }
        }
    };
    ...
}

【讨论】:

    【解决方案2】:
    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() {
            ...
        }
    }
    

    【讨论】:

    • 不行,我只想左键赋值l1,右键赋值l2。
    • @PlazmotechBinary:你试过这个答案吗?它在您的代码中不起作用,因为您试图将两次分配给最终变量,这是被禁止的。这个答案只分配一次,从而解决了问题。阅读编译器的错误信息。这很有意义。
    • 它不起作用,我只想在左键单击时分配 l1,如果右键单击编辑时分配 l2 - 哎呀重复了:P
    • @PlazmotechBinary 不要太嚣张,只要你什么都不懂,拜托!试试看,它有效。它不像你那样工作。
    • @PlazmotechBinary:这就是这段代码的作用。你至少明白上面的代码是做什么的了吗?
    【解决方案3】:

    匿名内部类需要使用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: Why do we use final keyword with anonymous inner classes?


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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        解决方案如@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 也应该可以正常工作,但要注意空指针。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多