Не создавайте экземпляр superclass в конструкторе подкласса, но полностью легальный

Я прочитал в руководстве scjp как следующее

Фактически, вы не можете создать новый объект, не вызвав не только конструктор фактического типа класса объекта, но и конструктор каждого из его суперклассов!

Например

public class Person{

}

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

Я не создаю экземпляр Person, но это законно.

Пожалуйста, объясните мне, спасибо за вашу помощь.

6 ответов

Решение

Всякий раз, когда вы создаете экземпляр подкласса, он сначала вызывает конструктор вашего суперкласса.

Вы можете найти больше об этом здесь: 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();

Выход:

Конструктор суперкласса называется

Подкласс конструктор называется

Во-первых, вам не нужно создавать родительский экземпляр (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);
   }
}

Что они на самом деле имеют в виду

  • Когда вы создаете объект подкласса, то есть вызывается его конструктор, тогда конструктор суперкласса вызывается internall
  • Это потому, что для конструктора по умолчанию без аргументов 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(){
    
    }
    

Это из-за цепочки конструктора:

Первым оператором внутри любого конструктора по умолчанию является super (); (Это вызов конструктора по умолчанию суперкласса).

Я не создаю экземпляр Person, но это допустимо, потому что у вас есть конструктор по умолчанию в классе Person. Таким образом, конструктор класса Employee может фактически вызвать конструктор суперкласса. Человек()

В итоге, текущий класс, в котором вы объявляете конструктор, весь конструктор до базового класса должен быть доступен через super(). Если нет, вы должны явно сделать их доступными, явно сделав вызов через super с соответствующими параметрами.

Нулевой конструктор суперкласса вызывается неявно.

Вы столкнулись с одной из странностей Java.

Если вы не определяете никаких конструкторов, по умолчанию или "без аргументов", конструктор определяется неявно. Это как невидимый код.

Если вы определяете какой-либо конструктор с аргументами или без аргументов, неявный конструктор по умолчанию исчезает.

Чтобы еще больше разгадать тайну, первая строка любого конструктора подкласса должна вызывать конструктор суперкласса. Если вы явно не вызываете его, конструктор no-args вызывается неявно.

Другие вопросы по тегам