
- •Программирование на Java
- •Глава 1 Введение в java. Основы языка.
- •Тема 1.1 Язык программирования java.
- •Тема 1.2 Состав пакета Java2.
- •Тема 1.3 Настройка среды окружения.
- •Тема 1.4 Структура Java-программы.
- •Тема 1.5 Набор текста, запуск и компиляция простейшей программы.
- •Тема 1.6 Подробное рассмотрение кода простейшей программы.
- •Тема 1.7. Создание программы в разных средах разработки.
- •Тема 1.8 Лексические основы языка
- •Тема 1.9 Элементарные типы данных.
- •Тема 1.10 Преобразование типов.
- •Арифметические операции
- •Операции сравнения
- •Тема 1.11 Кoнсольный ввод с помощью класса java.Util.Scanner
- •Тема 1.12 Классы-оболочки
- •Тема 1.13 Автоупакока и автораспаковка.
- •Тема 1.14 Операторы
- •1.14.1 Блок
- •1.14.2 Условный оператор if
- •1.14.4 Оператор цикла while
- •1.14.5 Оператор цикла do-while
- •1.14.6 Оператор цикла for
- •1.14.7 Оператор continue и метки
- •1.14.8 Оператор break
- •1.14.9 Оператор варианта switch
- •Тема 1.15 Статический импорт
- •Тема 1.16 Класс Math
- •Задания
- •Тема 1.17 Псевдослучайные числа
- •Тема 1.18 Генерация случайных чисел
- •Тема 1.19 Массивы в Java
- •1.19.1 Объявление и заполнение массива
- •1.19.2 Сортировка массива
- •Сортировка выбором
- •Сортировка методом пузырька
- •1.19.3 Многомерные массивы
- •Задания
- •1.19.4 Нерегулярные массивы
- •Глава 2 классы
- •Тема 2.1 Основы классов
- •Тема 2.2 Общая форма класса
- •Тема 2.3 Объявление объектов
- •Тема 2.4 Более подробное рассмотрение операции new
- •Тема 2.5 Присваивание переменных объектных ссылок
- •Тема 2.6 Знакомство с методами
- •Тема 2.7 Возвращение значения из метода
- •Тема 2.8 Добавление метода, принимающего параметры
- •Тема 2.9 Конструкторы
- •Тема 2.10 Сборка мусора
- •Тема 2.11 Перегрузка методов
- •Тема 2.12 Перегрузка конструкторов
- •Тема 2.13 Использование объектов в качестве параметров
- •Тема 2.14 Более пристальный взгляд на передачу аргументов
- •Тема 2.16 Рекурсия
- •Тема 2.17 Введение в управление доступом
- •Тема 2.18 Ключевое слово static
- •Тема 2.19 Ключевое слово final
- •Тема 2.20 Аргументы переменной длины
- •Тема 2.21 Строки и числа
- •Тема 2.22 Нумерованные типы
- •Глава 3 наследование и интерфейсы
- •Тема 3.1 Основы наследования
- •Тема 3.2 Наследование и доступ к членам класса
- •Тема 3.3 Конструкторы и наследование
- •Тема 3.4 Использование ключевого слова super для вызова конструктора суперкласса
- •Тема 3.5 Использование ключевого слова super для доступа к членам суперкласса
- •Тема 3.6 Многоуровневая иерархия
- •Тема 3.7 Когда вызываются конструкторы
- •Тема 3.8 Объекты подклассов и ссылки на суперклассы
- •Тема 3.9 Переопределение методов
- •Тема 3.10 Переопределение методов и поддержка полиморфизма
- •Тема 3.11 Использование абстрактных классов
- •Тема 3.12 Использование ключевого слова final
- •Тема 3.13 Предотвращение переопределения методов
- •Тема 3.14 Предотвращение наследования
- •Тема 3.15 Класс Object
- •Тема 3.16 Интерфейсы
- •3.16.1 Объявление интерфейса.
- •3.16.2 Реализация интерфейсов
- •3.16.3 Использование ссылок на интерфейсы
- •3.16.4 Переменные в составе интерфейсов
- •3.16.5 Наследование интерфейсов
- •Тема 3.17 Пакеты и ограничение доступа
- •Тема 3.18 Внутренние классы
- •3.18.1 Внутренние (inner) классы
- •3.18.2 Вложенные (nested) классы
- •3.18.3 Анонимные (anonymous) классы
- •Глава 4 Обработка исключительных ситуаций
- •Тема 4.1 Исключения в Java
- •Тема 4.2 Типы исключений
- •Тема 4.3 Неперехваченные исключения
- •Тема 4.4 Ключевые слова try и catch
- •Тема 4.6 Ключевое слово throw
- •Тема 4.7 Ключевое слово throws
- •Тема 4.8 Ключевое слово finally
- •Ошибка при выполнении метода1 java.Lang.ArithmeticException: Demo
- •Тема 4.9 Потомки Exception или написание своих классов ошибок
- •Глава 5 Универсальные типы. КоллекциИ
- •Тема 5.1 Общие сведения об универсальных типах
- •Тема 5.2 Универсальный класс с двумя параметрами типа
- •Тема 5.3 Ограниченные типы
- •Тема 5.4 Использование групповых параметров
- •Тема 5.5 Универсальные методы
- •Тема 5.6 Универсальные интерфейсы
- •Тема 5.7 Ошибки неоднозначности
- •Тема 5.8 Ограничения универсальных типов
- •Тема 5.9 Краткий обзор коллекций
- •5.9.1 Класс ArrayList
- •5.9.2 Класс LinkedList
- •5.9.3 Класс HashSet
- •5.9.4 Класс TreeSet
- •5.9.5 Доступ к коллекции через итератор
- •5.9.6 Алгоритмы коллекций
- •Глава 6 jdbc (Java DataBase Connectivity) Тема 6.1 Драйверы, соединения и запросы
- •Тема 6.2 Простое соединение и простой запрос
- •Тема 6.2 Класс ResultSet
- •Тема 6.3 Метаданные
- •Тема 6.4 Подготовленные запросы
- •Глава 7 Swing и пользовательский интерфейс
- •Тема 7.1 Общие сведения о swing
- •Тема 7.2 Архитектура mvc
- •Тема 7.3 Контейнер и компоненты
- •Тема 7.4 Простая программа, использующая средства Swing
- •Тема 7.5 Поддержка событий
- •Тема 7.6 Использование кнопок и обработка событий
- •Тема 7.7 Краткие сведения о диспетчерах компоновки
- •Тема 7.8 Пример использования jdbc и swing вместе
Тема 2.16 Рекурсия
В Java поддерживается рекурсия. Рекурсия – это процесс определения чего-либо в терминах самого себя. Применительно к программированию на Java рекурсия – это атрибут, который позволяет методу вызывать самого себя. Такой метод называют рекурсивным.
Классический пример рекурсии – вычисление факториала числа. Факториал числа N – это произведение всех целых чисел от 1 до N. Например, факториал 3 равен 1x2x3, или 6. В листинге 2.18 показано как можно вычислить факториал, используя рекурсивный метод.
Листинг 2.18
public class Factorial {
// это рекурсивный метод
public int fact(int n) {
int result;
if (n == 1) {
return 1;
}
result = fact(n - 1) * n;
return result;
}
}
public class Recursion {
public static void main(String args[]) {
Factorial f = new Factorial();
System.out.println("Факториал 3 равен " + f.fact(3));
System.out.println("Факториал 4 равен " + f.fact(4));
System.out.println("Факториал 5 равен " + f.fact(5));
}
}
Вывод этой программы имеет вид:
Факториал 3 равен 6 Факториал 4 равен 24 Факториал 5 равен 120
Для тех, кто не знаком с рекурсивными методами, работа метода fact () может быть не совсем понятна. Вот как работает этот метод. При вызове метода fact () с аргументом, равным 1, функция возвращает 1. В противном случае она возвращает произведение fact (n-1) *n. Для вычисления этого выражения программа вызывает метод fact () с аргументом 2. Это приведет к третьему вызову метода с аргументом, равным 1. Затем этот вызов возвратит значение 1, которое будет умножено на 2 (значение n во втором вызове метода). Этот результат (равный 2) возвращается исходному вызову метода fact () и умножается на 3 (исходное значение n). В результате мы получаем ответ, равный 6. В метод fact () можно было бы вставить операторы println (), которые будут отображать уровень каждого вызова и промежуточные результаты.
Когда метод вызывает самого себя, новым локальным переменным и параметрам выделяется место в стеке и код метода выполняется с этими новыми начальными значениями. При каждом возврате из рекурсивного вызова старые локальные переменные и параметры удаляются из стека, и выполнение продолжается с момента вызова внутри метода. Рекурсивные методы выполняют действия, подобные выдвиганию и складыванию телескопа.
Из-за дополнительной перегрузки ресурсов, связанной с дополнительными вызовами функций, рекурсивные версии многих подпрограмм могут выполняться несколько медленнее их итерационных аналогов. Большое количество обращений к методу могут вызвать переполнение стека. Поскольку параметры и локальные переменные сохраняются в стеке, а каждый новый вызов создает новые копии этих значений, это может привести к переполнению стека. В этом случае система времени выполнения Java будет генерировать исключение. Однако, вероятно, об этом можно не беспокоиться, если только рекурсивная подпрограмма не начинает себя вести странным образом.
Основное преимущество применения рекурсивных методов состоит в том, что их можно использовать для создания более понятных и простых версий некоторых алгоритмов, чем при использовании итерационных аналогов. Например, алгоритм быстрой сортировки достаточно трудно реализовать итерационным методом. А некоторые типы алгоритмов, связанных с искусственным интеллектом, легче всего реализовать именно с помощью рекурсивных решений.
При использовании рекурсивных методов нужно позаботиться о том, чтобы где-либо в программе присутствовал оператор if, осуществляющий возврат из рекурсивного метода без выполнения рекурсивного вызова. В противном случае, будучи вызванным, метод никогда не выполнит возврат. Эта ошибка очень часто встречается при работе с рекурсией. Поэтому во время разработки советуем как можно чаще использовать операторы println (), чтобы можно было следить за происходящим и прервать выполнение в случае ошибки.
Рассмотрим еще один пример рекурсии(листинг 2.19). Рекурсивный метод printArray () выводит первые i элементов массива values.
Листинг 2.19
public class RecTest {
public int values[];
public RecTest(int i) {
values = new int[i];
}
// рекурсивное отображение элементов массива
public void printArray(int i) {
if (i == 0) {
return;
} else {
printArray(i - 1);
}
System.out.println(" [" + (i - 1) + "] " + values[i - 1]);
}
}
public class Recursion2 {
public static void main(String args[]) {
RecTest ob = new RecTest(10);
int i;
for (i = 0; i < 10; i++) {
ob.values[i] = i;
}
ob.printArray(10);
}
}
Эта программа генерирует следующий вывод:
[0] 0 [1] 1 [2] 2 [3] 3 [4] 4 [5] 5 [6] 6 [7] 7 [8] 8 [9] 9