Java: руководство для начинающих
Шрифт:
Выполнение этой программы дает следующий результат: vaTest(int ...): Number of args: 3 Contents: arg 0: 1 arg 1: 2 arg 2: 3 vaTest(String, int ...): Testing: 2 Contents: arg 0: 10 arg 1: 20 vaTest(boolean ...): Number of args: 3 Contents: atg 0: true arg 1: false arg 2: false
В приведенном выше примере программы демонстрируются два способа перегрузки методов с аргументами переменной длины. Во-первых, типы параметров аргументов длины у перегружаемых методов могут отличаться. Это демонстрируют варианты метода vaTest (int . . .) и vaTest (boolean . . .). Напомним: многоточие обозначает, что соответствующий аргумент должен рассматриваться как массив указанного типа. Следовательно, как и при перегрузке обычных методов указываются разные типы параметров, так и перегрузке методов с аргументами переменной длины задаются
Второй способ перегрузки методов с аргументами переменной длины состоит в добавлении обьгчных аргументов. Он реализован в варианте метода vaTest (String, int . . .). В этом случае исполняющая система Java использует для выбора нужного варианта метода данные как о числе параметров, так и об их типах. Аргументы переменной длины и неоднозначность
При перегрузке методов с аргументами переменной длины может возникнуть довольно неожиданная ошибка. А возникает она вследствие неоднозначности в выборе метода. Рассмотрим в качестве примера следующую программу: // Перегрузка метода с аргументами переменной длины //и неоднозначность выбора метода. // //В этой программе имеется ошибка, и // поэтому она не будет компилироваться, class VarArgs4 { // Использование аргумента переменной длины типа int. static void vaTest(int ... v) { // ... } // Использование аргумента переменной длины типа boolean. static void vaTest(boolean ... v) { // ... } public static void main(String args[]) { vaTest(1, 2, 3); // OK vaTest(true, false, false); // OK vaTest; // Ошибка вследствие неоднозначности! } }
В этой программе перегрузка метода vaTest указана правильно, но она не компилируется. И причиной тому служит следующий вызов: vaTest; // Ошибка: неоднозначность вызова!
Переменное число аргументов подразумевает в том числе и нулевое их число, и поэтому приведенный выше вызов может быть интерпретирован и как vaTest (int . . .), и как vaTest (boolean . . .). Оба вызова допустимы, и поэтому обращение к данному методу неоднозначно.
Рассмотрим еще один пример неоднозначности при обращении к методу. Из приведенных ниже вариантов метода vaTest невозможно однозначно выбрать требуемый, несмотря на то, что в одном из вариантов метода, помимо аргумента переменной длины, присутствует также обычный аргумент. static void vaTest(int ... v) { // ... static void vaTest(int n, int ... v) { // ...
И хотя списки аргументов у обоих вариантов метода vaTest отличаются, компилятор все равно не может правильно выбрать вариант для следующего вызова: vaTest (1)
В самом деле, не понятно, нужно ли преобразовать этот вызов в vaTest (int . . .) с одним аргументом переменной длины или же в вызов vaTest (int, int . . .) без аргументов переменной длины? В итоге возникает неоднозначная ситуация.
Вследствие ошибок, подобных описанным выше, в ряде случаев приходится отказываться от перегрузки и присваивать методам разные имена. Кроме того, ошибки неоднозначности вскрывают концептуальные просчеты в программировании, которые можно исправить, более тщательно обдумав структуру программы. Упражнение для самопроверки по материалу главы 6
Допустим, имеется следующий фрагмент кода:class X { private int count; Является ли допустимым приведенный ниже фрагмент кода?class Y { public static void main(String args[]) { X ob = new X; ob.count = 10;.
Модификатор доступа должен __ объявлению члена класса.
Помимо очереди, в программах часто используется структура данных, которая называется стеком. Обращение к стеку осуществляется по принципу “первым пришел — последним обслужен44. Стек можно сравнить со стопкой тарелок, стоящих на столе.Последней берется тарелка, поставленная на стол первой. Создайте класс Stack, реализующий стек для хранения символов. Используйте методы push и pop для манипулирования содержимым стека. Пользователь класса Stack должен иметь возможность задавать размер стека при его создании. Все члены класса Stack, кроме методов push и pop , должны быть объявлены как private. (.Подсказка: в качестве заготовки можете воспользоваться классом Queue, изменив в нем лишь способ доступа к данным.)
Допустим, имеется следующий класс: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); } }