为什么克隆方法不应该在构建的克隆上调用任何非最终方法

时间:2016-08-21 11:14:15

标签: java final

我正在阅读有效的java第二版并且遇到了这一段。以下操作何时出现以及为什么会产生问题?

  

与构造函数一样,clone方法不应该调用任何非最终方法   正在建造的克隆方法(第17项)。如果clone调用   重写方法,此方法将在子类之前执行   它所定义的有机会在克隆中修复其状态,   很可能导致克隆和原始的腐败。   因此在前面讨论过put(key,value)方法   段落应该是最终的或私人的。 (如果它是私人的,那就是   可能是非最终公共方法的“辅助方法”。)

注意:我不知道当我们覆盖方法a()和父构造使用方法a()时。当我们从子类中执行super()时,调用new()而不是parent()a()。我理解克隆()

会发生同样的问题

1 个答案:

答案 0 :(得分:3)

仅仅因为protectedpublic非最终方法可被子类覆盖,这是初始化问题的足迹。假设overriden方法在初始化之前尝试访问某个字段,您将获得NullPointerException。假设它调用另一个依赖于在完全初始化之前无法保证的对象的特定状态的方法,这将导致更微妙的错误或程序的错误。

我所说的一切已经在你的书中了,所以让我们添加一个具体的例子:

public SpaceShip {
    private double oilLevelInLitres;
    private String model;

    public SpaceShip(double oilLevelInLitres, String model) {
       this.oilLevelInLitres = oilLevelInLitres;
       displayOilLevel();
       this.model = model;
    }

    public void displayOilLevel() {
       System.out.println("Oil level is currently " + oilLevelInLitres + " litres");
    }
}

public SpaceShipWithSecondaryReservoir {    
    public SpaceShip(double oilLevelInLitres, double secondaryReservoirOilLevelInLitres, String oilLevelInLitres) {
        super(oilLevelInLitres, oilLevelInLitres);
        this.secondaryReservoirOilLevelInLitres = secondaryReservoirOilLevelInLitres;
    }

    public void displayOilLevel() {
        System.out.println("Model " + model + " oil level is currently " + oilLevelInLitres + 
            " litres and " + secondaryReservoirOilLevelInLitres + " litres in the seconday reservoir");
    }
}

public Main() {
    public static void main(String[] args) {
        // will print "Model null oil level is currently 17.0 litres and 5.0 litres in 
        // the secondary reservoir"
        new SpaceShipWithSecondaryReservoir(17, 5, "Falcon-3X"); 
    }
}

在这个例子中你可以说父类可​​以在调用方法之前初始化model名称,而你是对的,但是在程序员编写父类构造函数的那一刻他正在制作假设显示方法不需要除油位之外的任何其他状态。

这是一个编程错误,可以通过在构造函数的末尾调用display方法来避免,但在更复杂的情况下,它不会那么微不足道。在构造函数中调用可覆盖的方法会使您暴露出一类错误,这些错误在您只调用final方法或私有方法时不存在。