繁体   English   中英

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

[英]Java referencing final variable before is has been initialized

我有这个超类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 ,它会用super(protection)调用Creature的构造函数。 Creature的构造函数中,方法canHaveAsProtection(p)被调用,它通过动态绑定获取Monster被覆盖的一个。 但是,这个覆盖版本使用的最终变量maxProtection尚未初始化......我该如何解决这个问题?

一些要点:

  • 只有Monster关心最大值,所以只有它应该知道这个概念
  • 所有生物必须具有> 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的构造函数公开。

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

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

把它从Monster推到Creature ,你很好。 你应该在Creature构造函数中有两个参数: protectionmaxProtection 如果maxProtection < 0protection超出0..maxProtection范围,则抛出IllegalArgumentException

这与你的初始化链有关。

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

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

怪物 - >生物 - >生物#setProtection->怪物#canHaveAsProtection ......

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

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

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

你的类应该是可靠的并且独立地初始化它的状态。 我认为你应该在构造函数中显式设置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);
}

基于其他答案中提到的原因,请执行以下操作:

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

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

由于< maxProtection校正+ 1似乎是您的预期逻辑。

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

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

您不应该在构造函数中调用公共方法。 相反,您可以将构造函数修饰符更改为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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM