class Bisection2{
private static double final EPS = le-8; // Константа
private double a = 0.0, b = 1.5, root; // Закрытые поля
public double getRoot(}{return root;} // Метод доступа
private double f(double x)
{
return x*x*x — 3*x*x + 3; // Или что-то другое
}
private void bisect(){ // Параметров нет —
// метод работает с полями экземпляра
double у = 0.0; // Локальная переменная — не поле
do{
root = 0.5 *(а + b);
у = f(root);
if (Math.abs(y) < EPS) break;
// Корень найден. Выходим из цикла
// Если на концах отрезка [a; root]
// функция имеет разные знаки:
if (f(а) * у < 0.0} b = root;
// значит, корень здесь
// Переносим точку b в точку root
//В противном случае:
else a = root;
// переносим точку а в точку root
// Продолжаем, пока [а; Ь] не станет мал
} while(Math.abs(b-a) >
= EPS);
}
public static void main(String[] args){
Bisection2 b2 = new Bisection2();
b2.bisect();
System.out.println("x = " +
b2.getRoot() + // Обращаемся к корню через метод доступа
", f() = " +b2.f(b2.getRoot()));
}
}
В описании метода f() сохранен старый, процедурный стиль: метод получает аргумент, обрабатывает его и возвращает результат. Описание метода bisect о выполнено в духе ООП: метод активен, он сам обращается к полям экземпляра b2 и сам заносит результат в нужное поле. Метод bisect () — это внутренний механизм класса Bisection2, поэтому он закрыт (private).
Имя метода, число и типы параметров образуют сигнатуру (signature) метода. Компилятор различает методы не по их именам, а по сигнатурам. Это позволяет записывать разные методы с одинаковыми именами, различающиеся числом и/или типами параметров.
Замечание
Тип возвращаемого значения не входит в сигнатуру метода, значит, методы не могут различаться только типом результата их работы.
Например, в классе Automobile мы записали метод moveTo(int x, int у) , обозначив пункт назначения его географическими координатами. Можно определить еще метод moveTo (string destination) для указания географического названия пункта назначения и обращаться к нему так:
oka.moveTo("Москва") ;
Такое дублирование методов называется перегрузкой (overloading). Перегрузка методов очень удобна в использовании. Вспомните, в главе 1 мы выводили данные любого типа на экран методом printin() не заботясь о том, данные какого именно типа мы выводим. На самом деле мы использовали разные методы t одним и тем же именем printin , даже не задумываясь об этом. Конечно, все эти методы надо тщательно спланировать и заранее описать в классе. Это и сделано в классе Printstream, где представлено около двадцати методов print() и println() .
Если же записать метод с тем же именем в подклассе, например:
class Truck extends Automobile{
void moveTo(int x, int y){
// Какие-то действия
}
// Что-то еще
}
то он перекроет метод суперкласса. Определив экземпляр класса Truck , например:
Truck gazel = new Truck();
и записав gazei.moveTo(25, 150) , мы обратимся к методу класса Truck . Произойдет переопределение (overriding) метода.
При переопределении права доступа к методу можно только расширить. Открытый метод public должен остаться открытым, защищенный protected может стать открытым.
Можно ли внутри подкласса обратиться к методу суперкласса? Да, можно, если уточнить имя метода, словом super , например, super.moveTo(30, 40) . Можно уточнить и имя метода, записанного в этом же классе, словом this , например, this.moveTo (50, 70) , но в данном случае это уже излишне. Таким же образом можно уточнять и совпадающие имена полей, а не только методов.
Данные уточнения подобны тому, как мы говорим про себя "я", а не "Иван Петрович", и говорим "отец", а не "Петр Сидорович".
Переопределение методов приводит к интересным результатам. В классе Pet мы описали метод voice() . Переопределим его в подклассах и используем в классе chorus , как показано в листинге 2.2.