【问题标题】:Accessing variables from inside anonymous class从匿名类内部访问变量
【发布时间】:2014-07-05 08:06:21
【问题描述】:

我有一个匿名类,我想从匿名访问外部类的一些变量。问题是,当我尝试访问它时,它的值与初始化时的值相同,即使我正在更改它在其他匿名类上的值。

这是修剪后的代码

public class WeaponCircle extends Entity {
    public static int TAG = gWorld.getNextTag();
    float power=99; // <<<--the variable
    public WeaponCircle(final gWorld world) {
        super(world);
        this.tag = TAG;

        setGroups(Scene.SLOWABLE);

        addMechanism(new IntervalMechanism(this,10) {
            @Override
            public void init() {
                super.init();
                    world.worldrenderer.setWorldShader("punchShockWave");
                    world.worldrenderer.getShader("punchShockWave").getShader().setUniformf("screenSize",  Tools.tempVec2.set(Gdx.graphics.getWidth(),Gdx.graphics.getHeight()));
                    power=4;
            }
            @Override
            public void die() {
                super.die();
                world.worldrenderer.setClearWorldShader();
            }
            @Override
            public void tick() {//this is called every frame
                if(power>0)power-=0.1f*Director.delta;
                Tools.con("debug0:"+power);    //<<--------------------debug0 ,prints correct value
            }
        });

        addMechanism(new MovementMechanism(this));

        addMechanism(new SpriteMechanism(this,"sprites/sprites.png",714,284,1,235,235,gWorld.RENDER_LAYER4));

        world.worldrenderer.addShader("punchShockWave", new Shader("shaders/default.ver","shaders/punch_shock_wave.frag",Shader.SCENE_SHADER));
        world.worldrenderer.getShader("punchShockWave").setListener(new ShaderParrametersListener(this) {
            @Override
            public void setParameters(Shader shader) {//called every frame
                WeaponCircle wc=(WeaponCircle)entity;//entity is the object that i passed in the constractor
                /*irrelevant code*/
                Tools.con("debug1:"+wc.power);  //<<--------------------debug1 ,prints always 99
                Tools.con("debug2:"+power);   //<<--------------------debug2 ,prints always 99
                /*irrelevant code*/
            }
        });
    }
}

ShaderParrametersListener(它是 Shader 类中的一个静态类)

public abstract static class ShaderParrametersListener{
    public Entity entity;
    abstract public void setParameters(Shader shader);
    public ShaderParrametersListener(){};
    public ShaderParrametersListener(Entity entity){this.entity=entity;}
}

我的实体系统基于匿名类,到目前为止我没有遇到任何问题,如果我再使用 1 个 IntervlMechanism 并从那里打印功率变量,我将得到正确的值。这只发生在 ShaderParrametersListener 类中。

【问题讨论】:

  • if(power&gt;0)power-=0.1f*Director.delta; - 我敦促您考虑空格(以及大括号)的可读性优势。
  • IntervalMechanism 是否声明了 power 字段?
  • @Henry ,不,不是,所有的电源外观都是指 WeaponCircle 类中的那个,三重检查
  • debug0、debug1、debug2的打印顺序是什么?
  • @newacct ,顺序为 debug0,debug1,debug2 。tick 和 setParameters() 都在同一个事件上执行,但 setParameters() 是最后调用的。而且一切都在一个线程上运行。跨度>

标签: java class anonymous-class


【解决方案1】:

我认为您的问题是您在构造函数中使用了 this 关键字。见Java - Leaking this in constructor

正如链接的答案所说,

“当一个对象的构造函数完成时,它被认为是完全初始化的。只有在对象完全初始化后才能看到对该对象的引用的线程保证看到该对象的最终字段的正确初始化值”。如果您将此泄漏到构造函数中的另一个线程,则没有这样的保证! '在构造函数的末尾'也可以由 VM 重新排序。”

我的猜测是 world.worldrenderer.getShader("punchShockWave").setListenerother 线程,它现在可以访问一个未完全构造的对象。

我建议在构造函数完成后找到一种方法来调用上述setListener 方法。

更新我看到power 字段不是 final,所以这可能会使我的假设无效,因为链接的问题似乎表明这个问题适用于仅限最终字段;但是,我仍然会尝试等到构造函数完成后再将this 传递给另一个对象。也许试试看它是否修复了这个错误。

【讨论】:

  • 哇,我在tick方法上移动了setListener(使用布尔'first'只调用一次),以便在对象的收缩完成并且问题消失后调用它,这是一个很好的答案,干得好,您将在 13 小时内获得赏金......
  • 我很高兴听到这个消息,SteveL。
  • 我想我在 windows(现在正在运行 linux)上没有遇到这个问题没有提到它,因为我不确定,这可能吗? vm的windows实现可能在线程管理方面做了一些不同的事情?另外,在我从另一个IntervalMechanism匿名类(或任何其他扩展的类)访问电源的情况下,我没有遇到这个问题(如问题中所述) WorldMechanism)。是否有可能在虚拟机的某些实现中,即使在此类中,我也会遇到上述问题?
  • 由于我对正在发生的事情的了解有限,我仍然会说“是的,您可能仍然会在当前工作的其他类中遇到问题。”并发是一件困难而棘手的事情,你可以做任何事情来消除任何不确定性或可能的错误是一件好事。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-16
  • 1970-01-01
相关资源
最近更新 更多