SteveL
SteveL

Reputation: 3389

Accessing variables from inside anonymous class

I have an anonymous class and I want to access some variables of the outer class from the anonymous.The problem is that always when I try to access it, it has the same value as when it was initialized even that i am changing its value on an other anonymous class.

this is the trimmed code

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 (its a static class inside the Shader class)

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

My entity system is based on anonymus classes and I didnt had any problem so far ,If i use 1 more IntervlMechanism and print the power variable from there ,I will get the correct value.This happens only in the ShaderParrametersListener class.

Upvotes: 1

Views: 204

Answers (1)

Jake Toronto
Jake Toronto

Reputation: 3584

I think your issue is that you are using the this keyword inside the constructor. See Java - Leaking this in constructor.

As the linked answer says,

"An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields". No such guarantee if you leak this to another thread in the constructor! Also 'at the end of the constructor' may be reordered by the VM."

My guess is that world.worldrenderer.getShader("punchShockWave").setListener is the other thread that now has access to an incompletely constructed object.

I'd recommend finding a way to call the above setListener method after your constructor has completed.

UPDATE I see that the power field is not final, so that may invalidate my hypothesis, as the linked question seems to indicate this problem holds for final fields only; however, I still would attempt to wait until after the constructor completes before passing this to another object. Maybe try it out and see if it fixes the bug.

Upvotes: 1

Related Questions