При подготовке своего ответа я обнаружил, что мне пришлось использовать слова суперкласс и подкласс в двух разных значениях. Я переименую классы в Thing
и Car
и буду использовать слова «суперкласс» и «подкласс» для общих понятий.
public class NewClass
{
public static class Thing
{
static void print()
{
System.out.println("print in superclass.");
}
}
public static class Car extends Thing
{
static void print()
{
System.out.println("print in subclass.");
}
}
public static void main(String[] args)
{
Thing A = new Thing();
Thing B = new Car(); //This line?
A.print();
B.print();
}
}
Выражение new Car()
всегда создает экземпляр типа Car
. Всегда. И результатом является [ссылка на] экземпляр Car
.
Теперь вы можете сохранить [ссылку на] экземпляр Car
в переменную любого типа, которая допускает Car
экземпляры. И это:
- a
Car
-типная переменная,
- переменная, объявленная с любым суперклассом
Car
(и это соответствует объявлению Thing B
),
- переменная, объявленная с типом интерфейса, прямо или косвенно реализованным
Car
.
Итак, что происходит со строкой кода
Thing B = new Car(); //This line?
Создает новый экземпляр Car
и поэтому, конечно, вызывает конструктор Car
(* 1) (* 2). И затем он сохраняет ссылку на этот экземпляр в переменной B
, которая учитывает все виды Thing
экземпляров, если они наследуются от Thing
, и, таким образом, поддерживает все, что ожидается от объекта Thing
.
И что происходит в
B.print();
Вызывает метод print()
экземпляра, на который ссылается B
. И поскольку этот экземпляр является экземпляром Car
, вы получите результаты Car.print()
, а не Thing.print()
.
Еще несколько замечаний:
Если бы Car
имел некоторые дополнительные методы, не найденные в Thing
(например, метод drive()
), компилятор не позволил бы вам вызывать их на B
, так как не все объекты Thing
имеют их , но только некоторые специализированные Thing
версии (т.е. Car
).
И я рекомендую привыкнуть к соглашениям об именах Java, например, что имена классов всегда начинаются с заглавной буквы, а переменные с нижнего регистра. Ребята из Java настолько привыкли к этим соглашениям, что мы находим действительно запутанным чтение кода, который не следует этим правилам.
(* 1) В вашем случае конструктор не определен явно, но автоматически генерируется компилятором Java.
(* 2) Конструктор подкласса всегда вызывает конструктор своего суперкласса и т. Д. Вплоть до конструктора Object
, чтобы инициализировать все аспекты экземпляра, который подкласс наследует от своего суперкласса.