有人能解释一下这段代码的工作原理吗? (它关于使用" final")

时间:2017-09-11 01:07:21

标签: java android libgdx

我是java编程的初学者,我目前正在研究libGDX的编程。在书中用libGDX开始Java游戏开发"有关如何制作一些基本游戏的说明。其中之一(游戏是处理鼠标和触摸输入的介绍)我们制作了一个游戏,其中气球在屏幕的左侧产生,这些气球继续向右侧移动,并且每个气球都从游戏中移除当你点击它,或当它离开屏幕时(当X大于屏幕的宽度时)  我在此代码中理解final的使用时遇到问题:

spawnTimer += delta;

// check time for next balloon spawn
if(spawnTimer > spawnInterval)
{
    spawnTimer -= spawnInterval;
    final Balloon b = new Balloon();
    b.addListener
    (
        new InputListener()
        {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int buttoon)
            {
                popped++;
                b.remove();
                return true;

            }
        }
    );
    mainStage.addActor(b);
}

if statement内的代码负责创建名为Balloon的actor的实例,并向其添加Input Listener,因此它将执行此代码:

popped++;
b.remove();
return true;

触摸时在本书中final并未用于创建Balloon的新实例,我只使用它,因为Android Studio让我这样做(它说我无法使用{{ 1}}因为它是一个将在实例中使用的代码或类似的东西),它似乎有效。我想知道为什么使用b.remove()有效。

当方法(update())完成它的事情时,final对象是否被处理掉了(这就是为什么它会赢得错误然后再次使用该行)?< / p>

执行final时,它将如何知道要删除的内容?

当我创建一个这样的实例时,我认为它给它起了一个名字,但它只是创建一个实例和一个指针,对吧? 所以,如果我放松了我刚刚创建的指针,我只能从实例内部(或者可能来自b.remove())获得另一个指针?

1 个答案:

答案 0 :(得分:-1)

所以,当你打电话给new InputListener() {时......你可能已经明白你正在创建一个匿名的内部类。使用匿名内部类的一个主要好处是可以在类成员(例如方法)中声明它,因此内部类可以访问封闭成员的元素,例如变量{{1 }}。您已捕获了封闭方法变量的值。在其他语言中,这通常被称为“封闭”。如果检查生成的字节码,您将看到新的内部类将具有类型为Balloon b的字段和类型为Balloon的构造函数参数。使用构造函数,变量Balloon将被复制到内部类的字段中。

在Java之前,有许多编程语言允许您以这种方式捕获值,但是其中许多语言在代码中引起了难以看到的问题,因为这些变量通常可以在方法中自由更改。调用b后,内部类的touchDown方法可能不会立即执行。如果该封闭方法中的代码在执行b.addListener之前为b分配了不同的对象,该怎么办?执行时应使用哪个touchDown的引用?原来的还是新的?

Java解决此问题的方法是坚持内部类捕获的任何方法变量都是final,这样可以确保以后在方法中不会更改它。如果您尝试捕获非final的变量,编译器将失败并显示错误。

作为旁注,Java 8样式的lambda表达式在内部编译为内部类,但实际上它们捕获变量的规则略有不同,但结果是相同的。而不是坚持捕获的任何变量是明确最终的,而是静态分析封闭方法以确保没有代码分配给该变量。如果是这样,您将收到一个错误,即该变量必须“有效”。最终