355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Герберт Шилдт » Java: руководство для начинающих (ЛП) » Текст книги (страница 15)
Java: руководство для начинающих (ЛП)
  • Текст добавлен: 6 октября 2016, 05:33

Текст книги "Java: руководство для начинающих (ЛП)"


Автор книги: Герберт Шилдт



сообщить о нарушении

Текущая страница: 15 (всего у книги 36 страниц)

Допустим, имеется следующий класс:class Test { int а; Test(int i) { a = i; } } Напишите метод swap (), реализующий обмен содержимым между двумя объектами типа Test, на которые ссылаются две переменные данного типа.

Правильно ли написан следующий фрагмент кода?class X { int meth(int a, int b) { ... } String meth(int a, int b) { ... }

Напишите рекурсивный метод, отображающий строку задом наперед.

Допустим, все объекты класса должны совместно пользоваться одной и той же переменной. Как объявить такую переменную?

Для чего может понадобиться статический блок?

Что такое внутренний класс?

Допустим, требуется член класса, к которому могут обращаться только другие члены этого же класса. Какой модификатор доступа следует использовать в его объявлении?

Имя метода и список его параметров вместе составляют __ метода.

Если методу передается значение типа int, то в этом случае используется передача параметра по __.

Создайте метод sum () с аргументами переменной длины для суммирования передаваемых ему значений типа int. Метод должен возвращать результат суммирования. Продемонстрируйте его в действии.

Можно ли перегружать метод с аргументами переменной длины?

Приведите пример неоднозначного вызова перегружаемого метода с переменным числом аргументов.

Глава 7 Наследование

Основные навыки и понятия

Основы наследования

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

Обращения к членам суперкласса с помощью ключевого слова super

Создание многоуровневой иерархии классов

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

Представление о ссылках на объекты подкласса из переменной суперкласса

Переопределение методов

Применение переопределяемых методов для организации динамического доступа

Абстрактные классы

Использование ключевого слова final

Представление о классе Object

Наследование является одним из трех основополагающих принципов объектно-ориентированного программирования, поскольку оно допускает создание иерархических классификаций. Благодаря наследованию можно создать общий класс, в котором определяются характерные особенности, присущие множеству связанных элементов. От этого класса могут затем наследовать другие, более конкретные классы, добавляя в него свои индивидуальные особенности.

В языке Java наследуемый класс принято называть суперклассом, а наследующий от него класс – подклассом. Следовательно, подкласс – это специализированный вариант суперкласса. Он наследует все переменные и методы, определенные в суперклассе, дополняя их своими элементами. Основы наследования

Наследование одних классов от других отражается в Java при объявлении класса. Для этой цели служит ключевое слово extends. Подкласс дополняет суперкласс, расширяя его.

Рассмотрим простой пример программы, демонстрирующий некоторые свойства наследования. В этой программе определен суперкласс TwoDShape, хранящий сведения о ширине и высоте двумерного объекта. Там же определен и его подкласс Triangle. Обратите внимание на то, что в определении подкласса присутствует ключевое слово extends. // Простая иерархия классов. // Класс, описывающий двумерные объекты, class TwoDShape { double width; double height; void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс класса TwoDShape для представления треугольников. // Класс Triangle наследует от класса TwoDShape class Triangle extends TwoDShape { String style; double area() { //Из класса Triangle можно обращаться к членам класса // TwoDShape таким же обраэом, как и к собственным членам. return width * height / 2; } void showStyle() { System.out.println("Triangle is " + style); } } class Shapes { public static void main(String args[]) { Triangle tl = new Triangle(); Triangle t2 = new Triangle(); // Все члены класса Triangle, даже унаследованные от класса // TwoDShape, доступны из объектов типа Triangle. tl.width = 4.0; tl.height = 4.0; tl.style = "isosceles"; t2.width = 8.0; t2.height = 12.0; t2.style = "right"; System.out.println("Info for tl: "); tl.showStyle(); tl.showDim(); System, out .println ("Area is " + tl.area()); System.out.println(); System.out.println("Info for t2: "); t2.showStyle(); t2.showDim(); System.out.println("Area is " + t2.area()); } }

Ниже приведен результат выполнения данной программы. Info for tl: Triangle is isosceles Width and height are 4.0 and 4.0 244 Java 7: руководство для начинающих, 5-е издание Area is 8.0 Info for t2: Triangle is right Width and height are 8.0 and 12.0 Area is 48.0

Здесь в классе TwoDShape определены атрибуты обобщенной двумерной фигуры, конкретным воплощением которой может быть квадрат, треугольник, прямоугольник и т.д. Класс Triangle представляет конкретную разновидность объекта типа TwoDShape, в данном случае – треугольник. Класс Triangle включает в себя все элементы класса TwoDObject, а в дополнение к ним – поле style и методы area () и showStyle (). Описание треугольника хранится в переменной экземпляра style, метод area () вычисляет и возвращает площадь треугольника, а метод showStyle () отображает геометрическую форму треугольника.

В класс Triangle входят все члены суперкласса TwoDShape, и поэтому в теле метода area () доступны переменные экземпляра width и height. Кроме того, с помощью объектов tl и t2 в методе main () можно непосредственно обращаться к переменным width и height, как будто они принадлежат классу Triangle. На рис. 7.1 схематически показано, каким образом суперкласс TwoDShape включается в состав класса Triangle.

Рис. 7.1. Схематическое представление класса Triangle

Несмотря на то что TwoDShape является суперклассом для класса Triangle, он по-прежнему остается независимым классом. Тот факт, что один класс является суперклассом другого класса, совсем не означает, что он не может быть использован самостоятельно. Например, следующий фрагмент кода считается вполне допустимым: TwoDShape shape = new TwoDShape(); shape.width = 10; shape.height = 20; shape.showDim();

Разумеется, объекту типа TwoDShape ничего не известно о подклассах своего класса TwoDShape, и он не может даже обратиться к ним.

Ниже приведена общая форма объявления класса, наследующего от суперкласса. class имя_подкласса extends имя_суперкласса { // тело класса }

Для каждого создаваемого подкласса можно указать только один суперкласс. Множественное наследование в Java не поддерживается, т.е. у подкласса не может быть несколько суперклассов. (Этим Java отличается от языка C++, где можно создать класс, производный сразу от нескольких классов. Об этом не следует забывать, преобразуя код C++ в код Java.) С другой стороны, вполне допустима многоуровневая иерархия, в которой один подкласс является суперклассом другого подкласса. И конечно же, класс не может быть суперклассом для самого себя.

Главное преимущество наследования заключается в следующем: как только будет создан суперкласс, в котором определены общие для множества объектов атрибуты, он может быть использован для создания любого числа более конкретных подклассов. А в каждом подклассе может быть точно выстроена своя собственная классификация. В качестве примера ниже приведен еще один подкласс, производный от суперкласса TwoDShape и инкапсулирующий прямоугольники. // Подкласс класса TwoDShape, представляющий прямоугольники, class Rectangle extends TwoDShape { boolean isSquareO { if(width == height) return true; return false; } double area() { return width * height; } }

В класс Rectangle входят все члены класса TwoDShape. Кроме того, он содержит метод is Square (), определяющий, является ли прямоугольник квадратом, а также метод area (), вычисляющий площадь прямоугольника. Доступ к членам класса и наследование

Как пояснялось в главе 6, члены класса зачастую объявляются закрытыми, чтобы исключить их несанкционированное или незаконное использование. Но наследование класса не отменяет ограничения, накладываемые на доступ к закрытым членам класса. Поэтому если в подкласс и входят все члены его суперкласса, то в нем все равно оказываются недоступными те члены суперкласса, которые являются закрытыми. Так, если сделать закрытыми переменные экземпляра width и height в классе TwoDShape, они станут недоступными в классе Triangle, как показано ниже. // Закрытые члены класса не наследуются. // Этот код не подлежит компиляции. // Класс, описывающий двумерные объекты, class TwoDShape { private double width; // Теперь эти переменные private double height; // объявлены как закрытые. void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс, производный от класса TwoDShape, // для представления треугольников., class Triangle extends TwoDShape { String style; double area() { // Обратиться к членам суперкласса, объявленным // как закрытые, нельзя. return width * height / 2; // Ошибка! Доступ запрещен. } void showStyle() { System.out.println("Triangle is " + style); } }

Класс Triangle не будет скомпилирован, поскольку ссылки на переменные экземпляра width и height в методе area () нарушают правила доступа. Эти переменные объявлены закрытыми (private), и поэтому они доступны только членам собственного класса. А его подклассам запрещено обращаться к ним.

Напомним, что член класса, объявленный закрытым (private), недоступен за пределами своего класса. Это ограничение распространяется и на подклассы.

На первый взгляд, ограничение на доступ к закрытым членам суперкласса из подкласса кажется трудно преодолимым, поскольку оно не дает во многих случаях возможности пользоваться закрытыми членами этого класса. Но на самом деле это не так. Как пояснялось в главе 6, для обращения к закрытым членам класса в программах на Java обычно используются специальные методы доступа. Ниже в качестве примера приведены видоизмененные классы TwoDShape и Triangle, в которых обращение к переменным экземпляра width и height осуществляется с помощью специальных методов доступа. // Применение методов доступа для установки и /// получения значений закрытых переменных. // Класс, описывающий двумерные объекты, class TwoDShape { private double width; // Теперь эти переменные private double height; // объявлены как закрытые. // Методы доступа к переменным экземпляра width и height. double getWidth() { return width; } double getHeight() { return height; } void setWidth(double w) { width = w; } void setHeight(double h) { height = h; } void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс, производный от класса TwoDShape, // для представления треугольников. class Triangle extends TwoDShape { String style; double area() { // Применение методов доступа, предоставляемых суперклассом. return getWidth() * getHeightO / 2; } void showStyle() { System.out.println("Triangle is " + style); } } class Shapes2 { public static void main(String args[]) { Triangle tl = new Triangle(); Triangle t2 = new Triangle(); tl.setWidth(4.0); tl. setHeight(4.0) ; tl.style = "isosceles"; t2.setWidth(8.0); t2.setHeight(12.0); t2.style = "right"; System.out.println("Info for tl: "); tl.showStyle(); tl.showDim(); System.out.println ("Area is " + tl.areaO); System.out.println() ; System.out.println("Info for t2: ") ; t2.showStyle(); t2.showDim(); System.out.println("Area is " + t2.area()); } } Конструкторы и наследование

В иерархии классов допускается, чтобы у суперклассов и подклассов были свои собственные конструкторы. В связи с этим возникает следующий резонный вопрос: какой конструктор отвечает за построение объекта подкласса: конструктор суперкласса, конструктор подкласса или же оба вместе? На этот вопрос можно ответить так: конструктор суперкласса конструирует родительскую часть объекта, а конструктор подкласса – производную часть этого объекта. И в этом есть своя логика, поскольку суперклассу неизвестны и недоступны любые элементы подкласса, а следовательно, их конструирование должно происходить раздельно. В приведенных выше примерах данный вопрос не возникал, поскольку они опирались на автоматическое создание конструкторов, используемых в Java по умолчанию. Но на практике конструкторы определяются явным образом в большинстве классов. Ниже будет показано, каким образом разрешается подобная ситуация.

Если конструктор определен только в подклассе, то все происходит очень просто: конструируется объект подкласса, а родительская часть объекта автоматически конструируется конструктором суперкласса, используемым по умолчанию. В качестве примера ниже приведен переработанный вариант класса Triangle, в котором определяется конструктор, а член style этого класса делается закрытым, так как теперь он устанавливается конструктором. // Добавление конструктора в класс Triangle. // Класс, описывающий двумерные объекты, class TwoDShape { private double width; // Теперь эти переменные private double height; // объявлены как закрытые. // Методы доступа к переменным экземпляра width и height. double getWidth() { return width; } double getHeight() { return height; } void setWidth(double w) { width = w; } void setHeight(double h) { height = h; } void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс, производный от класса TwoDShape, // для представления треугольников, class Triangle extends TwoDShape { private String style; // Конструктор. Triangle(String s, double w, double h) { // Инициализация родительской части объекта, // соответствующей классу TwoDShape. setWidth(w); setHeight(h); style = s; } double area() { return getWidth() * getHeightO / 2; } void showStyle() { System.out.println("Triangle is " + style); } } class Shapes3 { public static void main(String args[]) { Triangle tl = new Triangle("isosceles", 4.0, 4.0); Triangle t2 = new Triangle("right", 8.0, 12.0); System.out.println("Info for tl: "); tl.showStyle(); tl.showDim(); System.out.println ("Area is " + tl.areaO); System.out.println() ; System.out.println("Info for t2: "); t2.showStyle(); t2.showDim(); System.out.println("Area is " + t2.area()); } }

Здесь конструктор класса Triangle, помимо поля style, инициализирует также унаследованные члены класса TwoDClass.

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

Для вызова конструктора суперкласса служит следующая общая форма ключевого слова super: super (список_параметров);

где список_параметров обозначает параметры, необходимые для нормальной работы конструктора суперкласса. Вызов конструктора super () должен быть первым оператором в теле конструктора подкласса. Для того чтобы лучше понять особенности вызова super (), рассмотрим вариант класса TwoDShape из следующего примера программы, где определен конструктор, инициализирующий переменные экземпляра width и height: // Добавление конструкторов в класс TwoDShape. class TwoDShape { private double width; private double height; // Параметризированный конструктор объектов класса TwoDShape. TwoDShape(double w, double h) { width = w; height = h; } // Методы доступа к переменным экземпляра width и height. double getWidth() { return width; } double getHeight() { return height; } void setWidth(double w) { width = w; } void setHeight(double h) { height = h; } void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс, производный от класса TwoDShape, // для представления треугольников, class Triangle extends TwoDShape { private String style; Triangle(String s, double w, double h) { // Использование оператора super () для вызова // конструктора класса TwoDShape. super(w, h); // вызвать конструктор суперкласса style = s; } double area() { return getWidth() * getHeight() / 2; } void showStyle() { System.out.println("Triangle is " + style); } } class Shapes4 { public static void main(String args[]) { Triangle tl = new Triangle("isosceles", 4.0, 4.0); Triangle t2 = new Triangle("right", 8.0, 12.0); System.out.println("Info for tl: ") ; tl.showStyle(); tl.showDim(); System.out.println ("Area is " + tl.areaO); System.out.println(); System.out.println("Info for t2: ") ; t2.showStyle(); t2.showDim(); System.out.println("Area is " + t2.area()); } }

В конструкторе Triangle присутствует вызов конструктора super () с параметрами w и h. В результате управление получает конструктор TwoDShape (), инициализирующий переменные width и height значениями, передаваемыми ему в качестве параметров. Теперь класс Triangle уже не занимается инициализацией элементов суперкласса. Он должен инициализировать только собственную переменную экземпляра style. Конструктору TwoDShape () предоставляется возможность построить соответствующий подобъект так, как требуется для данного класса. Более того, в суперклассе TwoDShape можно реализовать функции, о которых не будут знать его подклассы. Благодаря этому код становится более устойчивым к ошибкам.

Любая форма конструктора, определенного в суперклассе, может быть вызвана с помощью оператора super (). Для выполнения выбирается тот вариант конструктора, который соответствует указываемым аргументам. В качестве примера ниже приведена расширенная версия классов TwoDShape и Triangle, содержащих конструкторы по умолчанию и конструкторы, принимающие один или более аргумент. // Добавление дополнительных конструкторов в класс TwoDShape. class TwoDShape { private double width; private double height; // Конструктор по умолчанию. TwoDShape() { width = height = 0.0; } // Параметризированный конструктор. TwoDShape(double w, double h) { width = w; height = h; } // Конструирование объекта с одинаковыми значениями // переменных экземпляра width и height. TwoDShape(double х) { width = height = x; } // Методы доступа к переменным экземпляра width и height. double getWidth() { return width; } double getHeight() { return height; } void setWidth(double w) { width = w; } void setHeight(double h) { height = h; } void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс, производный от класса TwoDShape,. // для представления треугольников, class Triangle extends TwoDShape { private String style; // Использование оператора super () для вызова // разных вариантов конструктора TwoDShape() . // Конструктор по умолчанию. Triangle() { super(); // вызвать конструктор суперкласса по умолчанию style = "null"; } // Параметризированный конструктор. Triangle(String s, double w, double h) { super(w, h); // вызвать конструктор суперкласса с двумя аргументами style = s; } // Конструктор с одним аргументом. Triangle(double х) { super(х); // вызвать конструктор суперкласса с одним аргументом style = "isosceles" } double area() { return getWidth() * getHeight() / 2; } void showStyle() { System.out.println("Triangle is " + style); } } class Shapes5 { public static void main(String args[]) { Triangle tl = new Triangle(); Triangle t2 = new Triangle("right", 8.0, 12.0); Triangle t3 = new Triangle(4.0); tl = t2; System.out.println("Info for tl: "); tl.showStyle(); tl.showDim(); System.out.println ("Area is " + tl.areaO); System.out.println() ; System.out.println("Info for t2: "); t2.showStyle(); t2.showDim(); System.out.println("Area is " + t2.area()); System.out.println(); System.out.println("Info for t3: "); t3.showStyle(); t3.showDim(); System.out.println("Area is " + t3.area()); System.out.println(); } }

Выполнение этой версии программы дает следующий результат: Info for tl: Triangle is right Width and height are 8.0 and 12.0 Area is 48.0 Info for t2: Triangle is right Width and height are 8.0 and 12.0 Area is 48.0 Info for t3: Triangle is isosceles Width and height are 4.0 and 4.0 Area is 8.0

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

Существует еще одна общая форма ключевого слова super, которая применяется подобно ключевому слову this, но ссылается на суперкласс данного класса. Эта общая форма обращения к члену суперкласса имеет следующий вид: super.член_класса

где член_класса обозначает метод или переменную экземпляра.

Данная форма ключевого слова super применяется в тех случаях, если член подкласса скрывает член суперкласса. Рассмотрим следующий пример несложной иерархии классов: // Применение ключевого слова super для предотвращения сокрытия имен. class А { int i; } // создать подкласс, расширяющий класс А. class В extends А { int i; // Эта переменная i скрывает переменную i из класса А. В (int a, int b) { // Оператор super.i ссылается на переменную i из класса А. super.i = а; // переменная i из класса А i = b; // переменная i из класса В } void show() { System, out .println ("i in superclass: 11 + super, i); System.out.println("i in subclass: " + i); } } class UseSuper { public static void main(String args[]) { В subOb = new В (1, 2)*; subOb.show(); } }

Результат выполнения данной программы выглядит следующим образом: i in superclass: 1 i in subclass: 2

Несмотря на то что переменная экземпляра i в классе В скрывает одноименную переменную в классе А, ключевое слово super позволяет обращаться к переменной i из суперкласса. Аналогичным образом ключевое слово super можно использовать для вызова методов суперкласса, скрываемых методами подкласса.

Пример для опробования 7.1. Расширение класса Vehicle

Для того чтобы продемонстрировать возможности наследования, расширим класс Vehicle, созданный в главе 4. Напомним, что класс Vehicle инкапсулирует данные о транспортных средствах и, в частности, сведения о количестве пассажиров, объеме топливного бака и потреблении топлива. Воспользуемся классом Vehicle в качестве заготовки для создания более специализированных классов. Например, транспортным средством, помимо прочих, является грузовик. Одной из важных характеристик грузовика является его грузоподъемность. Поэтому для создания класса Truck можно расширить класс Vehicle, добавив переменную экземпляра, хранящую сведения о допустимом весе перевозимого груза. В этом проекте переменные экземпляра будут объявлены в классе Vehicle как закрытые (private), а для обращения к ним будут созданы специальные методы доступа.

Последовательность действий

Создайте новый файл TruckDemo.java и скопируйте в него исходный код последней версии класса Vehicle, разработанной в главе 4.

Создайте класс Truck, исходный код которого приведен ниже. // Расширение класса Vehicle для грузовиков, class Truck extends Vehicle { private int cargocap; // грузоподъемность в фунтах // Конструктор класса Truck. Truck(int p, int f, int m, int c) { /* Инициализация переменных из класса Vehicle с помощью вызываемого конструктора этого класса. */ super(р, f, m); cargocap = с; } // Методы доступа к переменной cargocap. int getCargo() { return cargocap; } void putCargo(int c) { cargocap = c; } }

Здесь класс Truck наследует от класса Vehicle. В класс Truck добавлены новые члены cargocap, getCargo () и putCargo (). Кроме того, класс Truck содержит все элементы, определенные в классе Vehicle.

Объявите закрытыми переменные экземпляра в классе Vehicle, как показано ниже. private int passengers; // количество пассажиров private int fuelcap; // объем топливного бака в галлонах private int mpg; // потребление топлива в милях на галлон

Ниже приведен весь исходный код программы, в которой демонстрируется класс Truck. // Пример для опробования 7.1. // // Создание подкласса класса Vehicle для грузовиков. class Vehicle { private int passengers; // количество пассажиров private int fuelcap; // объем топливного бака в галлонах private int mpg; // потребление топлива в милях на галлон // Конструктор класса Vehicle. Vehicle(int р, int f, int m) { passengers = p; fuelcap = f; mpg = m; } // возвратить дальность действия транспортного средства int range() { return mpg * fuelcap; } // рассчитать объем топлива, требующегося // для прохождения заданного пути double fuelneeded(int miles) { return (double) miles / mpg; } // Методы доступа к переменным экземпляра, int getPassengers() { return passengers; } void setPassengers(int p) { passengers = p; } int getFuelcapO { return fuelcap; } void setFuelcap(int f) { fuelcap = f; } int getMpgO { return mpg; } void setMpg(int m) { mpg = m; } } // Расширение класса Vehicle для грузовиков, class Truck extends Vehicle { private int cargocap; // грузоподъемность в фунтах // Конструктор класса Truck. Truck(int p, int f, int m, int c) { /* Инициализация переменных из класса Vehicle с помощью вызываемого конструктора этого класса. */ super(р, f, m); ' cargocap = с; } // Методы доступа к переменной cargocap. int getCargo() { return cargocap; } void putCargo(int c) { cargocap = c; } } class TruckDemo { public static void main(String args[]) { // построить ряд новых объектов типа Truck Truck semi = new Truck(2, 200, 7, 44000); Truck pickup = new Truck(3, 28, 15, 2000); double gallons; int dist = 252; gallons = semi.fuelneeded(dist); System.out.println("Semi can carry " + semi.getCargo() + " pounds."); System.out.println("To go " + dist + " miles semi needs " + gallons + " gallons of fuel.n"); gallons = pickup.fuelneeded(dist); System.out.println("Pickup can carry " + pickup.getCargo() + " pounds."); System.out.println("To go " + dist + " miles pickup needs " + gallons + " gallons of fuel."); } }

Ниже приведен результат выполнения данной программы. Semi can carry 44000 pounds. То go 252 miles semi needs 36.0 gallons of fuel. Pickup can carry 2000 pounds. To go 252 miles pickup needs 16.8 gallons of fuel.

От класса Vehicle можно породить немало других подклассов. Например, в приведенной нщке заготовке класса, описывающего внедорожники, предусмотрена переменная, содержащая величину дорожного просвета для автомобиля. // Создание класса, описывающего внедорожники, class OffRoad extends Vehicle { private int groundClearance; // дорожный просвет в дюймах // ... }

Итак, имея в своем распоряжении суперкласс, определяющий общие свойства некоторых объектов, можно создать на его основе специализированные подклассы. Каждый подкласс дополняет свойства суперкласса собственными уникальными свойствами. В этом и состоит вся сущность наследования. Создание многоуровневой иерархии классов

В представленных до сих пор примерах программ использовались простые иерархии классов, состоявшие только из суперкласса и подкласса. Но в Java можно также строить иерархии, состоящие из любого числа уровней наследования. Как упоминалось выше, многоуровневая иерархия идеально подходит для использования одного подкласса в качестве суперкласса для другого подкласса. Так, если имеются три класса, А, в и С, то класс С может наследовать от класса В, а тот, в свою очередь, от класса А. В таком случае каждый подкласс наследует характерные особенности всех своих суперклассов. В частности, класс С наследует все члены классов В и А.

Для того чтобы стало понятнее назначение многоуровневой иерархии, рассмотрим следующий пример программы. В этой программе подкласс Triangle выступает в роли суперкласса для класса ColorTriangle. Класс ColorTriangle наследует все свойства классов Triangle и TwoDShape, а также содержит поле color, определяющее цвет треугольника. // Многоуровневая иерархия, class TwoDShape { private double width; private double height; // Конструктор по умолчанию. TwoDShape() { width = height = 0.0; } // Параметризированный конструктор. TwoDShape(double w, double h) { width = w; height = h; } // построить объект с одинаковыми значениями // переменных экземпляра width и height TwoDShape(double х) { width = height = x; } // Методы доступа к переменным экземпляра width и height. double getWidth() { return width; } double getHeight() { return height; } void setWidth(double w) { width = w; } void setHeight(double h) { height = h; } void showDim() { System.out.println("Width and height are " + width + " and " + height); } } // Подкласс, производный от класса TwoDShape. class Triangle extends TwoDShape { private String style; // Конструктор по умолчанию. Triangle() { super(); style = "null"; } Triangle(String s, double w, double h) { super(w, h); // вызвать конструктор суперкласса style = s; } // Конструктор с одним аргументом для построения треугольника. Triangle(double х) { super(х); // вызвать конструктор суперкласса style = "isosceles"; } double area() { return getWidth() * getHeightO / 2; } void showStyle() { System.out.println("Triangle is " + style); } } // Подкласс, производный от класса Triangle. // Класс ColorTriangle является подклассом, // производным от класса Triangle, который, в // свою очередь, расширяет класс TwoDShape. // Следовательно, в класс ColorTriangle входят переменные // и методы как из класса Triangle, так из класса TwoDShape. class ColorTriangle extends Triangle { private String color; ColorTriangle(String c, String s, double w, double h) { super(s, w, h); color = c; } String get.Color() { return color; } void showColor() { System.out.println("Color is " + color); } } class Shapes6 { public static void main(String args[ ]) { ColorTriangle tl = new ColorTriangle("Blue", "right", 8.0, 12.0); ColorTriangle.t2 = new ColorTriangle("Red", "isosceles", 2.0, 2.0); System.out.println("Info for tl: "); tl.showStyle(); tl.showDim(); tl.showColor(); System.out.println ("Area is " + tl.areaO); System.out.println (); System.out.println("Info for t2: "); // Из объекта типа ColorTriangle можно вызывать как его // собственные методы, так и методы его суперклассов. t2.showStyle (); t2.showDim(); t2.showColor (); System.out.println("Area is " + t2.area()); } }

Результат выполнения данной программы выглядит следующим образом: Info for tl: Triangle is right Width and height are 8.0 and 12.0 Color is Blue Area is 48.0 Info for t2: Triangle is isosceles Width and height are 2.0 and 2.0 Color is Red Area is 2.0


    Ваша оценка произведения:

Популярные книги за неделю