скачать книгу бесплатно
Эти переменные не создаются для каждого созданного объекта класса.
Они создаются только один раз для всех объектов класса.
И если мы изменим это значение, оно будет изменено для всех объектов.
Если мы не хотим, чтобы эта переменная менялась,
Мы можем сделать ее константой, добавив ключевое слово «final».
Мы можем также сделать это и для переменных экземпляра.
По соглашению, имена таких переменных пишутся в верхнем регистре, заглавными буквами.
Как показано здесь.
Значения финальных переменных могут быть установлены только один раз.
Таким образом, теперь у нас есть разные виды переменных.
С одной стороны, у нас есть локальные переменные.
Затем у нас есть переменные экземпляра, которые создаются для каждого объекта или экземпляра класса.
Каждый объект может иметь свое значение, хранящееся в этой переменной.
Мы можем использовать ключевое слово «this» для обозначения этих переменных.
И у нас есть переменные класса, которые создаются только один раз для всех объектов одного класса.
Они объявляются с ключевым словом «static».
Статические переменные инициализируются только один раз, при запуске выполнения кода, при загрузке класса.
Эти переменные будут инициализированы первыми, прежде чем будут инициализированы любые переменные экземпляра.
И если вы хотите сделать переменную экземпляра или переменную класса неизменной, вы добавляете ключевое слово «final».
Наследование
Рассмотрим две машины, принадлежащие к одному классу.
У них есть общие методы и поля, но в тоже время есть отличающиеся особенности.
И вместо того, чтобы создавать два разных объекта одного класса, а потом пытаться учесть их отличающиеся особенности с помощью отдельного кода, или создавать два разных несвязанных между собой класса, давайте сначала смоделируем общий класс автомобилей, а затем создадим класс легковых автомобилей и класс грузовиков, которые унаследуют общие поля и общие методы от общего класса автомобилей, но у них также будут и свои собственные поля, и методы.
Давайте посмотрим, как мы это делаем на Java.
Представьте, что у нас есть класс Car с этими полями и методами.
В частности, есть приватное поле количество пассажиров, noPass, которое содержит количество пассажиров в данный момент времени.
enter и exit- это методы, которые изменяют это число пассажиров.
Другой класс грузовиков имеет переменную загрузки, которая может быть изменена с помощью методов load и unload.
Имейте в виду, что не стоит называть переменную и метод одним и тем же именем.
Затем оба класса используют переменную цвет, а также методы для движения вперед
и назад.
Что мы можем сделать для упрощения кода, так это сначала определить универсальный класс для транспортных средств.
Этот класс будет иметь поля и методы, общие для всех автомобилей – в нашем случае – для легковых автомобилей и грузовиков.
Затем мы можем определить классы, car и truck, которые наследуют поля и методы от этого общего для них класса.
Vehicle будет называться суперклассом классов car и truck, и классы car и truck являются подклассами класса Vehicle.
Теперь мы можем определить класс car, расширив класс Vehicle, и добавить дополнительные поля и методы, которые может иметь легковой автомобиль.
А для грузовых автомобилей мы делаем то же самое: расширяем класс Vehicle такими полями и методами, которые необходимы.
Все остальные поля и методы унаследованы от класса Vehicle.
Обратите внимание, что мы не раскрыли тело конструктора.
Это требует дальнейшего объяснения и новых концепций.
Но вы должны знать, что класс может иметь несколько подклассов, тогда как класс не может быть подклассом более чем одного класса.
У одного класса не может быть двух суперклассов, не может быть двух родителей.
Таким образом, мы знаем, что один класс может расширить другой класс.
Например, если класс B расширяет класс A, это означает, что он наследует его поля и методы.
И это можно сделать многократно.
То есть класс B может быть расширен, например, классом C.
Теперь мы хотим проанализировать вопрос о том, как определить конструктор класса A, который расширяет другой класс.
В нашем определении класса vehicle и класса car, где класс car расширяет класс vehicle, мы определяем конструктор для класса vehicle, который инициализирует приватное поле color.
И с этим не никаких проблем.
Но как мы можем определить тело конструктора car, с учетом двух аргументов, целого числа для количества пассажиров и строки для цвета?
Класс car наследует все методы от класса vehicle – перемещение вперед и назад, и все его поля, в данном случае, только color.
Но поле color является приватным полем и не может быть доступно извне класса vehicle.
Это относится также и к подклассам, и это очень важно.
Поэтому неправильно присваивать значение «с» полю color в классе car.
Мы не можем получить к этому полю доступ, потому что оно является приватным.
Мы можем использовать только публичный метод, например, конструктор.
Теперь, если мы хотим вызвать конструктор суперкласса, мы используем ключевое слово super.
Здесь вы это видите.
super (c) – вызов конструктора vehicle (c).
Таким образом, мы сможем инициализировать поле color из подкласса.
Вызов конструктора суперкласса должен быть перед любым другим кодом в теле конструктора подкласса.
Например, сначала установить количество пассажиров, а затем вызвать супер будет неправильным.
Вы должны сначала вызвать супер, а затем включить любой другой вызов, который вам может понадобиться.
Здесь мы видим другой пример.
У нас есть класс A с подклассом B, а класс B с подклассом C.
Диаграмма справа от вас показывает отношения наследования.
Класс A имеет конструктор без аргументов, который печатает строку A, пробел.
В классе B мы видим, что есть также конструктор без аргументов, который правильно вызывает сначала конструктор суперкласса A, затем печатает строку B, пробел.
В классе C конструктор без аргументов сначала вызывает конструктор его суперкласса B, а затем печатает строку C точка.
Теперь, что происходит, когда мы создаем новый объект класса C?
Конструктор C вызывает конструктор B, который в свою очередь, вызывает конструктор А.
Таким образом, печатается: A, пробел, B, пробел, C точка.
Подводя итог, первое, что нам нужно сделать в конструкторе подкласса, это вызвать конструктор суперкласса.
Приведение типов
Давайте посмотрим снова на эту иерархию классов.
Легковой автомобиль и грузовик являются подклассами или производными классами класса vehicle.
Вопрос в том, если ли у нас есть объект класса car, мы можем использовать его там, где должны быть объекты класса vehicle?
Например, в переменной vehicle?
И наоборот, можем ли мы поместить объекты суперкласса там, где должны быть объекты подкласса?
И если да, то при каких обстоятельствах?
Мы говорим о кастинге или приведении при преобразовании объекта из одного класса к другому связанному классу.
Представьте себе, что у нас есть переменная vehicle, которая хранит объект vehicle, и переменная car, с сохраненным в нем объектом car.
Можем ли мы присвоить объект car переменной vehicle и наоборот?
Мы говорим о приведение к базовому типу при преобразовании объекта из класса в суперкласс.
И переход от подкласса к суперклассу всегда возможен.
Объекты подкласса наследуют все от суперкласса.
Поэтому все, что вы хотите сделать с переменной суперкласса, применимо к объекту подкласса.
Чтобы привести к базовому типу объект, вы можете указать суперкласс в круглых скобках, как вы здесь видите.
Но вы также можете не делать это, как вы видите в последней строке.
Мы говорим о понижающем приведении при конвертации объекта от класса к его подклассу.
Теперь мы хотим заставить vehicle стать car.
Мы переходим от общего класса к более конкретному классу, и это должно быть сделано явно.
В этом примере мы объявляем переменную типа vehicle, но храним в ней car.
Таким образом, мы можем явно понизить эту переменную для хранения car, который находится в переменной v.
Вы должны быть очень осторожны при кастинге вверх и вниз.
Мы объявляем переменную v, и мы храним в ней car.
Мы можем это сделать, поскольку car является vehicle.
Однако вы не можете привести v в переменную truck.
Вы не можете сделать приведение между классами, полученными из одного класса.
Вы не можете превратить car в truck или truck в car.