2016-08-21 79 views
0

我正在阅读有效的Java第2版,并且遇到了这一段。什么时候出现以下行为,为什么它会产生问题?为什么克隆方法不能在正在构建的克隆上调用任何非最终方法

像一个构造函数,一个克隆方法不应以正在建设中(第17项)的克隆任何非最终 方法。如果克隆调用 重写的方法,则此方法将在 的子类之前执行,该子类定义的子类有可能修复其克隆中的状态, 很可能导致克隆和原始文件损坏。 因此,前面的 段落中讨论的put(key,value)方法应该是final或private。 (如果是私有的,它是 想必“助手方法”的非最终公共方法。)

注:我不知道,当我们覆盖的方法()和父构造器使用方法()。当我们从子类new()中执行super()时,会调用a()而不是父类的a()。我知道同样的问题发生在克隆()

+0

我已经添加了一个例子来说明 – Dici

回答

3

只是因为protectedpublic non-final方法是由子类覆盖,这是脚步到初始化问题。假设重写方法试图在初始化之前访问一个字段,你会得到一个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或private方法时不存在的错误。