Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПРИС_шпоры.doc
Скачиваний:
3
Добавлен:
01.03.2025
Размер:
3.46 Mб
Скачать

18. Java. Абстрактные, виртуальные, конечные и статические методы.

Статические методы и поля

Для того чтобы не надо было создавать объект класса Math (и других аналогичных классов) каждый раз, когда надо вызвать sin (и другие подобные функции), введено понятие статических методов (static method; иногда в русском языке они называются статичными). Статический метод (отмечаемый словом static в описании) можно вызвать, не создавая объекта его класса. Поэтому можно писать

double x = Math.sin(1);

вместо

Math m = new Math(); double x = m.sin(1);

Ограничение, накладываемое на статические методы, заключается в том, что в объекте this они могут обращаться только к статическим полям и методам. Статические поля имеют тот же смысл, что и в C++: каждое существует только в одном экземпляре.

Абстрактность

В Java все методы являются виртуальными в терминологии C++: при вызове метода, по-разному определённого в базовом и наследующем классах, всегда производится проверка времени выполнения. Абстрактным методом (описатель abstract) в Java называется метод, для которого заданы параметры и тип возвращаемого значения, но не тело. Абстрактный метод определяется в классах-наследниках. В C++ то же самое называется чисто виртуальной функцией. Для того чтобы в классе можно было описывать абстрактные методы, сам класс тоже должен быть описан как абстрактный. Объекты абстрактного класса создавать нельзя.

При описании класса Pet мы не можем задать в методе voice () никакой полезный алгоритм, поскольку у всех животных совершенно разные голоса. В таких случаях мы записываем только заголовок метода и ставим после закрывающей список параметров скобки точку с запятой. Этот метод будет абстрактным (abstract), что необходимо указать компилятору модификатором abstract . Если класс содержит хоть один абстрактный метод, то создать его экземпляры, а тем более использовать их, не удастся. Такой класс становится абстрактным, что обязательно надо указать модификатором abstract . Как же использовать абстрактные классы? Только порождая от них подклассы, в которых переопределены абстрактные методы. Зачем же нужны абстрактные классы? Не лучше ли сразу написать нужные классы с полностью определенными методами, а не наследовать их от абстрактного класса? Для ответа снова обратимся к листингу 2.2. Хотя элементы массива singer [] ссылаются на подклассы Dog, Cat, Cow , но все-таки это переменные типа Pet и ссылаться они могут только на поля и методы, описанные в суперклассе Pet . Дополнительные поля подкласса для них недоступны. Попробуйте обратиться, например, к полю k класса Dog , написав singer [0].k . Компилятор "скажет", что он не может реализовать такую ссылку. Поэтому метод, который реализуется в нескольких подклассах, приходится выносить в суперкласс, а если там его нельзя реализовать, то объявить абстрактным. Таким образом, абстрактные классы группируются на вершине иерархии классов. Кстати, можно задать пустую реализацию метода, просто поставив пару фигурных скобок, ничего не написав между ними, например: void voice(){} Получится полноценный метод. Но это искусственное решение, запутывающее структуру класса. Замкнуть же иерархию можно окончательными классами.

В языке Java определение метода включает его объявление и реализацию. Определение метода всегда указывается в теле класса.

Метод может иметь модификаторы доступа, возвращать значение и получать параметры.

Метод может иметь следующие модификаторы:

public, protected или private -модификаторы доступа;

static - модификатор метода класса.

abstract, final, native или synchronized.

Для модификаторов доступа метода определены следующие правила:

public указывает, что данный метод будет доступен везде, где доступен класс, в котором он определен;

protected указывает, что данный метод будет доступен как внутри пакета, содержащего объявление класса, в котором он определен, так и внутри любого подкласса данного класса;

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

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

Метод, не имеющий модификатора static, называется методом экземпляра. Метод экземпляра может быть вызван только для созданного экземпляра класса или подкласса. Такой метод нельзя вызывать непосредственно, квалифицируя его именем класса.

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

Если статический метод определен как final-метод, то он не может быть переопределен.

Например:

// Файл A.java

package classa;

public class A implements B {

public A() { }

static int b=1;

public int Metod1(){return a;}

public static int Metod2(){

return 0;} //Статический метод

}

interface B {

final public static int a=1;

// Статическая переменная

int Metod1();

}

// Файл C.java

package classa;

public class C extends A {

public C() { }

static int b=3;

public int Metod1(){return a;}

public static int Metod2(){return 77;}

public static void main(String[] args) {

System.out.println(A.Metod2());

System.out.println(C.Metod2());

}

}

При переопределении методов их модификаторы доступа должны совпадать. Так, нельзя переопределить метод, имеющий модификатор доступа public, методом с модификатором доступа private.

Абстрактный метод указывается модификатором abstract. Такой метод никогда не имеет тела метода: вместо фигурных скобок, ограничивающих тело метода, объявление метода завершается точкой с запятой.

Абстрактные методы можно объявлять только в абстрактных классах или интерфейсах. Объявление абстрактного метода в классе, не имеющем модификатора abstract, приводит к ошибке компиляции. Любой подкласс абстрактного класса, который сам не является абстрактным классом, должен определять реализацию всех наследуемых не реализованных абстрактных методов.

Например:

public class A extends AA implements B {

public A() { }

public int Metod1(){return 0;}

public static int Metod2(){return 0;}

int Metod3(){return 0;}

public int Metod4(){return 0;}

}

interface B {

int Metod1();

abstract int Metod4();

}

abstract class AA{

abstract int Metod3();

}

Методы, объявленные с модификатором private, не могут быть абстрактными методами, так как они недоступны вне тела класса. Статические методы также не могут выступать в качестве абстрактных методов, так как считаются конечными и не могут быть переопределены.

Объявление метода с модификатором final запрещает его последующее переопределение. Такие методы называются конечными методами, и по умолчанию считается, что private-метод всегда является конечным методом.

Методы, объявленные с модификатором native, могут иметь реализацию на другом языке программирования. Эти методы используются для написания машинно-зависимого кода. native-методы в Java-программе не имеют тела метода.

Synchronized-методы выполняются с блокировкой:

для метода класса выполняется блокировка класса,

для метода экземпляра - блокировка объекта.

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

Метод может возвращать значение заданного типа. В этом случае:

перед именем метода указывается тип возвращаемого значения;

в теле метода присутствует оператор return, определяющий возвращаемое значение.

Если метод не имеет возвращаемого значения, то он должен быть объявлен с ключевым словом void, указывающим на отсутствие возвращаемого значения.

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