如何打破超类构造链?

时间:2015-11-16 16:25:56

标签: java class inheritance

class Animal {
    protected Animal(){
        System.out.println("ANIMAL CONSTRUCTOR");
    }
    public void move(){
        System.out.println("ANIMAL Move");
    }
}

class Dog extends Animal{
    public Dog(){
        System.out.println("Dog Constructor");
    }
    public void move(){
        System.out.println("Dog move");
    }

}


public class Test {
    public static void main(String args[]){
    Dog d = new Dog();
    d.move();
    }
}

上面的代码产生以下结果:

ANIMAL CONSTRUCTOR 
Dog Constructor
Dog move

似乎在创建dog实例时,它默认情况下也会调用Animal构造函数(隐式)。

这很奇怪,因为我在考虑明确调用super()可以做同样的工作。

有没有办法打破这个构造函数链,让我的dog实例只调用Dog构造函数?

如果没有,是否有理由呢?

2 个答案:

答案 0 :(得分:8)

  

似乎在创建dog实例时,它默认情况下也会调用Animal构造函数(隐式)。

  

这很奇怪,因为我在考虑明确调用super()可以做同样的工作。

您可以,是的,但如果不这样做,编译器会在子类构造函数的开头插入对super()(没有args)的调用。允许您显式执行此操作的原因是您可能希望调用接受参数的超类构造函数。

  

有没有办法打破这个构造函数链并让我的dog实例只调用Dog构造函数?

没有

  

如果没有,是否有理由呢?

由于Dog 是(n) Animal,因此Animal类必须有机会初始化Animal - 具体正在创建的对象的功能。

考虑:

class Animal {
    private Something useful;

    Animal() {
        this.useful = /*...something useful...*/;
    }
}

class Dog extends Animal {
    private String breed;

    Dog(String breed) {
        this.breed = breed;
    }
}

构造Dog实例时,在内存中它看起来像这样:

+-------------+
|     Dog     |
+-------------+
| useful: ... |
| breed:  ... |
+-------------+

Dog实例是由Animal定义的内容与Dog定义的内容的组合。

现在,假设Animal的构造函数从未被调用过:useful会有什么价值?对! null(因为我将其声明为对象类型)。但是Animal的代码非常清楚地期望构造函数将useful设置为有用的东西。如果我们能以某种方式绕过Animal的构造函数,我们就会打破这个类。

答案 1 :(得分:1)

当您实例化子类时,无法阻止调用Animal构造函数。基本上是因为基类可能包含需要设置的字段。

(注意,隐式基类java.lang.Object的构造函数也被调用。你的问题更多的是关于"错过了一个构造函数"继承heirarchy中的某个地方。

如果Animal不包含任何字段,您可以将interface设为Town - Age Class - Pop Wherever - 0-9 - 1000 Wherever - 10-19 - 2000 Wheverer - 20-29 - 2500 。然后它将没有构造函数。以这种方式使用接口允许您在非动物的对象(例如车辆)上定义类似移动的方法。然后,您就陷入了一种名为 composition 的编程范式。