Java 有人能解释一下这个代码是如何工作的吗?(它是关于使用“final”的)

Java 有人能解释一下这个代码是如何工作的吗?(它是关于使用“final”的),java,android,libgdx,Java,Android,Libgdx,我是java编程的初学者,目前正在学习为libGDX编程。在《用libGDX开始Java游戏开发》一书中,有关于如何制作一些基本游戏的说明。其中之一(介绍鼠标和触摸输入处理的游戏)我们制作了一个游戏,气球在屏幕左侧生成,这些气球不断向右侧移动,当你点击它或当它离开屏幕时(当X大于屏幕宽度时),每个气球都会从游戏中移除 我在理解此代码中的final用法时遇到问题: spawnTimer += delta; // check time for next balloon spawn if(spawn

我是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);
}
popped++;
b.remove();
return true;
if语句
中的代码负责创建名为
Balloon
的参与者实例,并向其添加一个
输入侦听器
,以便执行以下代码:

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);
}
popped++;
b.remove();
return true;
当它被触摸时。在书中,
final
没有用于创建
Balloon
的新实例,我之所以使用它,是因为Android Studio让我这么做(它说我不能使用
b.remove()
,因为它是一个将在实例内部使用的代码或类似的东西),而且它似乎可以工作。我想知道为什么使用
final
有效

当方法(update())完成它的工作时,
final
对象是否被处理掉了(这就是为什么它在再次使用该行时不会出错)

执行
b.remove()
时,它如何知道要删除什么

当我创建这样一个实例时,我以为它给了它一个名称,但它只是创建了一个实例和一个指针,对吗?
因此,如果我松开了刚才创建的指针,我只能从实例内部(或者从
主干
)获取另一个指针。

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

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

Java解决这个问题的方法是坚持内部类捕获的任何方法变量都是final,这确保了它以后在方法中不会被更改。如果您试图捕获一个非final的变量,编译器将失败并出错


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

该变量必须是
final
,因为它在内部类中使用。这意味着引用在初始化后不能更改,而不是永远存在。是的,在java中创建对象只会生成一个新实例并更新指针。并且y您不能直接与Java中的指针交互,因此您必须在应用程序中的某个位置维护引用。Java中的垃圾收集会自动删除您不再持有引用的任何内容。lambda不会编译为许多(所有?)中的内部类主要的编译器。除此之外,确实没有任何规范说明这种情况会发生。感谢@brick!我现在大部分的Java工作都是在Android上进行的,到目前为止,获得Java 8支持的最常见的方式是使用RetroLambda,它使用本地类来支持lambda。类似地,Jack compiler将lambda编译成本地类,用于较旧的运行时(但Jack编译器已被Google删除)。谢谢你的回答。这对我帮助很大。还有一个问题:有人能告诉我为什么我在触地方法中返回true吗?我知道它需要它,因为它的返回类型是Boolean,但为什么?如果代码在事件发生时执行,为什么我需要返回true?是否存在我希望返回false的情况?这是s类从实现InputProcessor的类扩展而来,要求我定义触地方法,它返回false。为什么?我建议您阅读。如果返回false,您将不会收到触地拖动或触地事件,而且该事件不会被视为“已处理”,父组件可能会有机会处理它。