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构造函数?
如果没有,是否有理由呢?
答案 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 的编程范式。