【问题标题】:Don't create supperclass instance in contructor of subclass, but fully legal不要在子类的构造函数中创建超类实例,但完全合法
【发布时间】:2013-07-05 09:58:52
【问题描述】:

我在 scjp 指南中阅读如下

事实上,你不能在不调用的情况下创建一个新对象,而不仅仅是 对象的实际类类型的构造函数,但也是 每个超类的构造函数!

例如

public class Person{

}

public class Employee extends Person{
   public Employee(){
}
}

我没有创建 Person 实例,但它是合法的。

请给我解释一下,谢谢你的帮助。

【问题讨论】:

  • 没有得到您的问题?你能解释更多吗?
  • 我的意思是,我没有在 Employee 的构造函数中创建 Person 实例,但它是合法的。

标签: java oop constructor constructor-overloading


【解决方案1】:

当你实例化一个子类时,它会首先调用你的超类的构造函数。

您可以在此处找到更多相关信息:JSL §8.8.7

Person.java

public class Person {
    public Person() {
        System.out.println("Super class constructor called");
    }
}

Employee.java

public class Employee extends Person {
    public Employee() {
        System.out.println("Sub class constructor called");
    }
}

如果您随后实例化您的员工:

Employee e = new Employee();

输出:

调用超类构造函数

调用子类构造函数

【讨论】:

  • 其实没有回答问题:“我没有创建 Person 实例,但它是合法的。”
【解决方案2】:

他们真正的意思是

  • 当您创建子类对象时,即调用它的构造函数,然后内部调用超类构造函数
  • 这是因为对于默认的无参数构造函数,有一个默认的super() 调用超类构造函数。
  • 这就像类层次结构一样一直持续到Object 类。

实际上,如果你不在超类中编写无参数构造函数,那么子类声明会抛出编译器错误。

public class Super {

    public Super(int num){

    }
}

public class Sub extends Super {

}

这里,Sub 类将无法编译,给出错误Implicit super constructor Super() is undefined for default constructor,因为它在超类中找不到无参数构造函数,因为 default no-argument constructor 即编译器提供的将隐式调用 super()

  • 仅当没有定义其他构造函数时,编译器才提供默认的无参数构造函数
  • 由于我们已经显式定义了Super(int num),我们将必须显式创建无参数构造函数,如下所示。

      public Super(){
    
    }
    

【讨论】:

    【解决方案3】:

    首先,您不必创建父实例 (Parent) 来实例化子类 (Employee)。你一定是理解错了。

    调用父类的构造函数并不意味着创建一个新的父实例对象(你不是用new调用它,所以不会创建新的实例)。您正在创建一个子实例,为此,由于继承,您需要首先调用父级的构造函数。例如,想象一下父类具有必须在构造函数中初始化的private 字段(例如private final 字段)。该字段不能从子类访问,但可以从父类构造函数初始化。您需要在子实例中初始化该字段,唯一的方法是调用super()

    在这种情况下,Person 有一个默认构造函数,默认调用它,不需要显式调用它。

    但如果Person 没有默认构造函数,则需要显式调用它。例如:

    public class Person{
        private final String name;
        public Person(final String name) {
            this.name = name;
        }
    }
    
    public class Employee extends Person {
       public Employee() {
       }
    }
    

    这不会编译。您需要修改Employee,使其显式调用Person 构造函数。例如:

    public class Employee extends Person {
       public Employee(final String name) {
          super(name);
       }
    }
    

    【讨论】:

    • +1 因为这是唯一不完全专注于构造函数链接的答案,而是解释了 Person 和 Employee 之间的关系。每当创建一个 Employee 对象时,它也是一个 Person 对象。
    • @GyroGearless 是的,没有其他答案可以解释 OP 问题:“我没有创建 Person 实例,但它是合法的。” 但他们得到了支持和接受。只是像往常一样奇怪的东西:D
    【解决方案4】:

    隐式调用超类的空构造函数。

    【讨论】:

      【解决方案5】:

      这是因为构造函数链接:

      any构造函数中的第一条语句默认是super();(这是对超类默认构造函数的调用)。

      我没有创建 Person 实例,但它是合法的: 那是因为您在 Person 类中有一个默认构造函数。所以Employee类构造函数实际上可以调用超类构造函数。 人()

      底线,您要在其中声明构造函数的当前类,所有构造函数直到基类都应该可以通过 super() 访问。如果没有,您必须通过使用适当参数的 super 显式调用来显式地使它们可访问。

      【讨论】:

        【解决方案6】:

        你遇到了 java 的一个怪事。

        如果您没有定义 任何 构造函数,默认或“无参数”,构造函数是 隐式 定义的。就像看不见的代码。

        如果您定义 any 构造函数、args 或没有 args,则隐式默认构造函数消失。

        为了进一步复杂化,任何子类构造函数的第一行必须是调用超类的构造函数。如果您不显式调用一个,则隐式调用无参数构造函数。

        【讨论】:

          猜你喜欢
          • 2018-09-25
          • 1970-01-01
          • 2017-11-24
          • 1970-01-01
          • 1970-01-01
          • 2013-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多