之前的Java引用最终变量已初始化

时间:2013-05-22 20:37:48

标签: java inheritance final dynamic-binding

我有这个超类Creature及其子类Monster。现在我遇到了这个问题,即在没有初始化的情况下引用最终变量。

public class Creature {

    private int protection;

    public Creature(int protection) {
        setProtection(protection);
    }

    public void setProtection(int p) {
        if(!canHaveAsProtection(p))
            throw new Exception();
        this.protection = p;
    }

    public boolean canHaveAsProtection(int p) {
        return p>0;
    }
}

和子类:

public class Monster extends Creature {

    private final int maxProtection;

    public Monster(int protection) {
        super(protection);
        this.maxProtection = protection;
    }

    @Override
    public boolean canHaveAsProtection(int p) {
        return p>0 && p<maxProtection
    } 
}

正如您所看到的,当我初始化新的Monster时,它会使用Creature调用super(protection)的构造函数。在Creature的构造函数中,调用方法canHaveAsProtection(p),通过动态绑定获取Monster中的覆盖方法。但是,此覆盖版本使用尚未初始化的最终变量maxProtection ... 我怎么解决这个问题?

7 个答案:

答案 0 :(得分:1)

有些观点:

  • 只有Monster关心最大值,所以只有它应该知道这个概念
  • 所有生物必须有保护&gt; 0
  • 不要将范围检查推迟到单独的方法
  • 上限和下限检查不需要在同一个地方
  • 使用装饰器模式解决问题

总而言之,您的代码应如下所示:

public class Creature {

    private int protection;

    protected Creature() {
    }

    public Creature(int protection) {
        setProtection(protection);
    }

    public void setProtection(int p) {
        if (p < 0)
            throw new IllegalArgumentException();
        this.protection = p;
    }
}

public class Monster extends Creature {

    private final int maxProtection;

    private Monster(int protection) {
        this.maxProtection = protection;
        setProtection(protection);
    }

    @Override
    public void setProtection(int p) {
        if (protection > maxProtection)
            throw new IllegalArgumentException();
        super.setProtection(p);;
    }

    public static Monster create(int protection) {
        Monster monster = new Monster(protection);
        monster.validate();
        return monster;
    }
}

您尚未显示validate()方法死亡的内容,但如果只需要保护检查,我会删除它和静态工厂方法并将Monster的构造函数设为公开。

答案 1 :(得分:0)

Monster不会在您发布的代码中展开Creature

如果是,我认为Monster没有理由拥有最终变量。 Creature应该有最终变量,而Monster应该只是访问它。如果需要对保护进行最大值验证,那么在我看来,所有Creature个实例都应该拥有它。

将它从Monster推到Creature,你没事。您应该在Creature构造函数中有两个参数:protectionmaxProtection。如果IllegalArgumentExceptionmaxProtection < 0超出范围protection,则会引发0..maxProtection

答案 2 :(得分:0)

这与你的初始化链有关。

在初始化父级之前,必须完全初始化子级。

目前,它看起来像......

  

Monster-&GT; Creature-&GT;生物#setProtection-&GT;怪物#canHaveAsProtection   ...

其中maxProtextion尚未初始化,因为Creature constrcutor尚未返回。

一个解决方案是推迟初始化一些方法,也许在构造函数可以调用的init方法中

答案 3 :(得分:0)

在构造函数中调用公共方法确实是一种不好的做法,特别是当你希望将它子类化时。

你的班级应该是坚实的,并独立地初始化它的状态。 我认为你应该在构造函数中明确设置protection变量:

public Creature(int protection) {
    this.protection = protection;
}

如果您确实想在构造函数中验证参数,请将常用功能提取到私有方法:

public Creature(int protection) {
    Assert.isTrue(isProtectionValid(p));
    this.protection = protection;
}

private static boolean isProtectionValid(int p) {
    return p > 0;
}

public boolean canHaveAsProtection(int p) {
    return isProtectionValid(p);
}

答案 4 :(得分:0)

由于其他答案中提到的原因,请执行:

public Creature(int protection) {
    this.protection = protection;
}

public Monster(int protection) {
    super(protection + 1);
    this.maxProtection = protection;
}

由于+ 1

,因此修正< maxProtection似乎是您的预期逻辑

答案 5 :(得分:0)

如何覆盖设置保护设置max first en而不是超级设置保护。

    @override
   public void setProtection(int p) {
        this.maxProtection = p;
    super.setProtection(p);
    }

答案 6 :(得分:0)

您不应该在构造函数中调用公共方法。相反,您可以将构造函数修饰符更改为protected / private,并使用调用验证的工厂方法:

public class Creature {
    private int protection;

    protected Creature(int protection) {
        this.protection = protection;
    }

    public void setProtection(int protection) {
        if (!canHaveAsProtection(protection))
            throw new IllegalArgumentException();
        this.protection = protection;
    }

    public boolean canHaveAsProtection(int protection) {
        return protection > 0;
    }

    protected void validate() {
        if (!canHaveAsProtection(this.protection))
            throw new IllegalArgumentException();
    }

    public static Creature create(int protection) {
        Creature creature = new Creature(protection);
        creature.validate();
        return creature;
    }
}

Monster

public class Monster extends Creature {

    private final int maxProtection;

    private Monster(int protection) {
        super(protection);
        this.maxProtection = protection;
    }

    @Override
    public boolean canHaveAsProtection(int p) {
        // I changed '<' to '<=' because '<' wouldn't work anyway
        return p > 0 && p <= maxProtection;
    }

    public static Monster create(int protection) {
        Monster monster = new Monster(protection);
        monster.validate();
        return monster;
    }
}