У меня есть анонимный класс, и я хочу получить доступ к некоторым переменным внешнего класса от анонимного. Проблема в том, что всегда, когда я пытаюсь получить к нему доступ, он имеет то же значение, что и при его инициализации, даже если я изменяю его значение на другой анонимный класс.
это обрезанный код
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.
Я думаю, ваша проблема в том, что вы используете this
ключевое слово внутри конструктора. См. Java - Утечка этого в конструкторе.
Как говорится в ответном ответе,
"Объект считается полностью инициализированным, когда его конструктор заканчивается. Поток, который может видеть только ссылку на объект после того, как этот объект был полностью инициализирован, гарантированно увидит правильно инициализированные значения для этих конечных полей объекта". Нет такой гарантии, если вы пропустите это в другой поток в конструкторе! Также "в конце конструктора" может быть переупорядочено VM ".
Я предполагаю, что world.worldrenderer.getShader("punchShockWave").setListener
- это другой поток, который теперь имеет доступ к неполному конструированному объекту.
Я бы рекомендовал найти способ вызова вышеуказанного метода setListener
после завершения вашего конструктора.
ОБНОВЛЕНИЕ Я вижу, что power
поле не является final
, поэтому может привести к аннулированию моей гипотезы, поскольку связанный вопрос, похоже, указывает, что эта проблема выполняется только для окончательных полей; однако я все равно попытаюсь подождать, пока конструктор не завершит передачу this
объекта другому объекту. Возможно, попробуйте и посмотрите, исправляет ли он ошибку.
if(power>0)power-=0.1f*Director.delta;
- Я призываю вас рассмотреть преимущества удобочитаемости пробелов (и даже скобок).IntervalMechanism
объявляетpower
поле?