【问题标题】:How to break super class constructor chain?如何打破超类构造函数链?
【发布时间】:2016-02-17 19:51:59
【问题描述】:
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 构造函数?

如果没有,有什么原因吗?

【问题讨论】:

标签: java class inheritance


【解决方案1】:

好像dog实例创建的时候,也默认(隐式)调用Animal构造函数。

是的。

这很奇怪,因为我认为显式调用 super() 可以完成同样的工作。

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

有没有办法打破这个构造函数链,让我的狗实例只调用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 实例是Animal 定义的内容和Dog 定义的内容的组合。

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

【讨论】:

  • sosuper()是用来明确继承还是从很多其他构造函数中选择?
  • @KeonKim:是的。 super()(字面意思,没有争论)纯粹是风格问题。例如,我总是这样做,正是因为这些原因:为了清楚发生了什么,特别是我称之为无参数版本。但是有些人相当合理地争辩说我不应该这样做,因为无论如何编译器总是这样做,所以他们发现看到它明确地写出来很不和谐。当然,当您调用super(with, args, here) 时,这是必需的,因为编译器永远不会为您这样做。 (即使超类没有无参数构造函数。)
【解决方案2】:

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

(请注意,隐式基类java.lang.Object 的构造函数也被调用。您的问题更多是关于继承层次结构中某处的“遗漏构造函数”)。

如果不包含任何字段,您可以将 Animal 设为 interface。那么它将没有构造函数。以这种方式使用接口允许您在非动物对象(例如车辆)上定义类似运动的方法。然后,您偶然发现了一种称为 composition 的编程范式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    相关资源
    最近更新 更多