Чтение онлайн

на главную

Жанры

Java: руководство для начинающих
Шрифт:

Ниже приведен результат выполнения данной программы. Factorials using recursive method. Factorial of 3 is 6 Factorial of 4 is 24 Factorial of 5 is 120 Factorials using iterative method. Factorial of 3 is 6 Factorial of 4 is 24 Factorial of 5 is 120

Действия нерекурсивного метода fact I не требуют особых пояснений. В нем используется цикл, в котором числа, начиная с 1, последовательно умножаются друг на друга, постепенно образуя произведение, дающее факториал.

Рекурсивный метод f actR действует несколько сложнее. Когда метод factR вызывается с аргументом, равным 1, он возвращает 1, а иначе —произведение, определяемое из выражения factR(n-l)*n. Для вычисления этого выражения вызывается метод factR с аргументом п-1. Этот процесс повторяется до тех пор, пока значение переменной п не окажется равным 1, после чего из предыдущих вызовов данного метода начнут возвращаться полученные значения. Например, при

вычислении факториала 2 первый вызов метода factR повлечет за собой второй вызов того же самого метода, но с аргументом 1. В результате метод возвратит значение 1, которое затем умножается на 2 (т.е. исходное значение переменной п). В результате всех этих вычислений будет получен факториал, равный 2. По желанию в тело метода factR можно ввести операторы println , чтобы сообщать, на каком именно уровне осуществляется очередной вызов, а также отображать промежуточные результаты вычислений.

Когда метод вызывает самого себя, в системном стеке распределяется память для новых локальных переменных и параметров, и код метода выполняется с этими новыми переменными и параметрами с самого начала. При рекурсивном вызове метода не создается его новая копия, но лишь используются его новые аргументы. А при возврате из каждого рекурсивного вызова старые локальные переменные и параметры извлекаются из стека, и выполнение возобновляется с точки вызова в методе. Рекурсивные методы можно сравнить по принципу действия с постепенно сжимающейся и затем распрямляющейся пружиной.

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

Главное преимущество рекурсии заключается в том, что она позволяет реализовать некоторые алгоритмы яснее и проще, чем итерационным способом. Например, алгоритм быстрой сортировки довольно трудно реализовать итерационным способом. А некоторые задачи, например искусственного интеллекта, очевидно, требуют именно рекурсивного решения. При написании рекурсивных методов следует непременно указать в соответствующем месте условный оператор, например if, чтобы организовать возврат из метода без рекурсии. В противном случае возврат из вызванного однажды рекурсивного метода может вообще не произойти. Подобного рода ошибка весьма характерна для реализации рекурсии в практике программирования. Поэтому рекомендуется пользоваться операторами, содержащими вызовы метода println , чтобы следить за происходящим в рекурсивном методе и прервать его выполнение, если в нем обнаружится ошибка. Применение ключевого слова static

Иногда требуется определить такой член класса, который будет использоваться независимо от всех остальных объектов этого класса. Как правило, доступ к члену класса организуется посредством объекта этого класса, но в то же время можно создать член класса для самостоятельного применения без ссылки на конкретный экземпляр объекта. Для того чтобы создать такой член класса, достаточно указать в самом начале его объявления ключевое слово static. Если член класса объявляется как static, он становится доступным до создания любых объектов своего класса и без ссылки на какой-нибудь объект. С помощью ключевого слова static можно объявлять как переменные, так и методы. Наиболее характерным примером члена типа static служит метод main , который объявляется таковым потому, что он должен вызываться виртуальной машиной Java в самом начале выполняемой программы.

Для того чтобы воспользоваться членом типа static за пределами класса, достаточно указать имя этого класса с оператором-точкой. Но создавать объект для этого не нужно. В действительности член типа static оказывается доступным не по ссылке на объект, а по имени своего класса. Так, если требуется присвоить значение 10 переменной count типа static, являющейся членом класса Timer, то для этой цели можно воспользоваться следующей строкой кода: Timer.count = 10;

Эта форма записи подобна той, что используется для доступа к обычным переменным экземпляра посредством объекта, но в ней указывается имя класса, а не объекта. Аналогичным образом можно вызвать метод типа static, используя имя класса и оператор-точку.

Переменные, объявляемые как static, по существу являются глобальными. Когда же объекты объявляются в своем классе, копия переменной типа static не создается. Вместо этого все экземпляры класса совместно пользуются одной и той же переменной типа static. Ниже приведен пример программы, демонстрирующий отличия переменной, объявленной как static, от обычной переменной экземпляра. // Применение статической переменной, class StaticDemo { int х; // обычная переменная экземпляра static int у; // статическая переменная — это одна копия, // совместно используемая всеми объектами. // возвратить сумму значений переменной экземпляра х и // статической переменной у. int sum { return х + у; } } class SDemo { public static void main(String args[]) { StaticDemo obi = new StaticDemo; StaticDemo ob2 = new StaticDemo; // У каждого объекта имеется своя копия переменной экземпляра, obl.x = 10; ob2.х = 20; System.out.println("Of course, obl.x and ob2.x " + "are independent."); System.out.println("obi.x: " + obl.x + "\nob2.x: " + ob2.x); System.out.println ; // Все объекты совместно пользуются одной общей // копией статической переменной. System.out.println("The static variable у is shared."); StaticDemo.y = 19; System.out.println("Set StaticDemo.y to 19."); System.out.println("ob1.sum : " + obl.sum); System.out.println("ob2.sum: " + ob2.sum); System.out.println; StaticDemo.y = 100; System.out.println("Change StaticDemo.y to 100"); System.out.println("ob1.sum : " + ob1.sum); System.out.println("ob2.sum: " + ob2.sum); System.out.println; } }

Выполнение этой программы дает следующий результат: Of course, obl.x and ob2.x are independent, obl.x: 10 ob2.x: 20 The static variable у is shared. Set StaticDemo.y to 19. obi.sum: 29 ob2.sum: 39 Change StaticDemo.y to 100 obi.sum: 110 ob2.sum: 120

Нетрудно заметить, что статическая переменная у используется как объектом obi, так и объектом оЬ2. Изменения в ней оказывают влияние на весь класс, а не только на его экземпляр.

Метод типа static отличается от обычного метода тем, что его можно вызывать по имени его класса, не создавая экземпляр объекта этого класса. Пример такого вызова уже приводился ранее. Это был метод sqrt типа static, относящийся к классу Math из стандартной библиотеки классов Java. Ниже приведен пример программы, в которой объявляется статическая переменная и создается метод типа static. // Применение статического метода, class StaticMeth { static int val = 1024; // статическая переменная // Статический метод, static int valDiv2 { return val/2; } } class SDemo2 { public static void main(String args[]) { System.out.println("val is " + StaticMeth.val); System.out.println("StaticMeth.valDiv2: " + StaticMeth.valDiv2); StaticMeth.val = 4; System.out.println("val is " + StaticMeth.val); System.out.println("StaticMeth.valDiv2: " + StaticMeth.valDiv2); } }

Выполнение этой программы дает следующий результат: val is 1024 StaticMeth.valDiy2 : 512 val is 4 StaticMeth.valDiv2: 2

На применение методов типа static накладывается ряд следующих ограничений.

В методе типа static допускается непосредственный вызов только других методов типа static.

Для метода типа static непосредственно доступными оказываются только другие данные типа static, определенные в его классе.

В методе типа static должна отсутствовать ссылка this.

В приведенном ниже классе код статического метода valDivDenom создан некорректно. class StaticError { int denom =3; // обычная переменная экземпляра static int val = 1024; // статическая переменная /* Ошибка! К нестатическим переменным нельзя обращаться из статического метода. */ static int valDivDenom { return val/denom; // не подлежит компиляции! } } Статические блоки

Иногда для подготовки к созданию объектов в классе должны быть выполнены некоторые инициализирующие действия. В частности, может возникнуть потребность установить соединение с удаленным сетевым узлом или задать значения некоторых статических переменных перед тем, как воспользоваться статическими методами класса. Для решения подобных задач в Java предусмотрены статические блоки. Статический блок выполняется при первой загрузке класса, еще до того, как класс будет использован для каких-нибудь других целей. Ниже приведен пример применения статического блока. // Применение статического блока, class StaticBlock { static double root0f2; static double root0f3; // Этот блок выполняется при загрузке класса. static { System.out.println("Inside static block."); root0f2 = Math.sqrt(2.0); rootOf3 = Math.sqrt(3.0); } StaticBlock(String msg) { System.out.println (msg) ; } } class SDemo3 { public static void main(String args[]) { StaticBlock ob = new StaticBlock("Inside Constructor"); System.out.println("Square root of 2 is " + StaticBlock.rootOf2); System.out.println("Square root of 3 is " + StaticBlock.rootOf3) ; } }

Поделиться:
Популярные книги

Мужчина моей судьбы

Ардова Алиса
2. Мужчина не моей мечты
Любовные романы:
любовно-фантастические романы
8.03
рейтинг книги
Мужчина моей судьбы

Разбуди меня

Рам Янка
7. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
остросюжетные любовные романы
5.00
рейтинг книги
Разбуди меня

Неверный

Тоцка Тала
Любовные романы:
современные любовные романы
5.50
рейтинг книги
Неверный

На границе империй. Том 9. Часть 2

INDIGO
15. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 2

Небо для Беса

Рам Янка
3. Самбисты
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Небо для Беса

Жребий некроманта 3

Решетов Евгений Валерьевич
3. Жребий некроманта
Фантастика:
боевая фантастика
5.56
рейтинг книги
Жребий некроманта 3

Черный Маг Императора 7 (CИ)

Герда Александр
7. Черный маг императора
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Черный Маг Императора 7 (CИ)

Его маленькая большая женщина

Резник Юлия
Любовные романы:
современные любовные романы
эро литература
8.78
рейтинг книги
Его маленькая большая женщина

Зауряд-врач

Дроздов Анатолий Федорович
1. Зауряд-врач
Фантастика:
альтернативная история
8.64
рейтинг книги
Зауряд-врач

Законы Рода. Том 4

Flow Ascold
4. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 4

Проводник

Кораблев Родион
2. Другая сторона
Фантастика:
боевая фантастика
рпг
7.41
рейтинг книги
Проводник

Возмездие

Злобин Михаил
4. О чем молчат могилы
Фантастика:
фэнтези
7.47
рейтинг книги
Возмездие

Восход. Солнцев. Книга XI

Скабер Артемий
11. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга XI

Курсант: Назад в СССР 10

Дамиров Рафаэль
10. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 10