Материал предоставлен https://it.rfei.ru

Другие модификаторы для классов

К классам верхнего уровня и вложенным классам можно применить модификаторы abstract и final.

Абстрактные (abstract) классы

Класс может быть определен с ключевым словом abstract для указания на то, что он не может быть инстанцирован. Такой выбор для класса оправдан, если абстракция, которую он представляет, является всеобщей и для ее практического использования требуется специализация. Класс Vehicle может быть задан как abstract, чтобы представить абстракцию транспортного средства, так как создание экземпляров этого класса не имеет большого смысла. Создание же экземпляров неабстрактных классов, таких как Car и Bus, будет более разумным, так как здесь абстракция становится более конкретной.

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

В примере 4.8 в описании абстрактного класса Light присутствует абстрактный метод kwhPrice в строке (1). Это заставляет его подклассы обеспечивать реализацию этого метода. Подкласс TubeLight обеспечивает реализацию для метода kwhPrice в строке (2). Класс Factory создает экземпляр класса TubeLight в строке (3). Ссылочные переменные абстрактного класса можно объявить, как показано в строке (4), но сам абстрактный класс не может быть инстанцнрован, что показано в строке (5). Ссылка на абстрактный класс может указывать на объекты подкласса, как показано в строке (6).

Пример 4.8. Абстрактные классы

abstract class Light {
    // Fields
    int     noOfWatts;       // Мощность
    boolean indicator;       // Включено или выключено
    String  location;        // Размещение

    // Instance methods
    public void switchOn()  { indicator = true; }
    public void switchOff() { indicator = false; }
    public boolean isOn()   { return indicator; }

    // Abstract Instance Method
    abstract public double kwhPrice();               // (1) Нет тела метода
}

class TubeLight extends Light {
    // Fields
    int tubeLength;

    // Implementation of inherited abstract method.
    public double kwhPrice() { return 2.75; }        // (2)
}

public class Factory {
    public static void main(String[] args) {
        TubeLight cellarLight = new TubeLight();     // (3) OK
        Light nightLight;                            // (4) OK
    //  Light tableLight = new Light();              // (5) Ошибка компиляции
        nightLight = cellarLight;                    // (6) OK
        System.out.println("KWH price: " + nightLight.kwhPrice());
    }
}

Вывод программы:

KWH price: 2.75

Интерфейсы задают только прототипы методов, а не реализацию, т.е. они по своей природе неявно абстрактны (не могут быть инстанцированы). Хотя это и допустимо, но излишне объявлять интерфейс с ключевым словом abstract.

Неизменяемые (final) классы

Класс может быть объявлен как final, чтобы указать, что от него нельзя наследовать, т.е. нельзя объявить ни один подкласс неизменяемого класса. Это предполагает, что ни один из методов, объявленных в этом классе, не может быть переопределен. Другими словами, поведение неизменяемого класса не может быть изменено путем объявления подклассов. Класс задает нижнюю границу в иерархии наследования реализации. Только класс, определение которого является полным (т.е. реализованы все его методы), может быть объявлен как final.

Неизменяемый класс должен быть завершен, в то время как абстрактный класс считается неполным. Поэтому в одно и то же время класс не может быть и неизменяемым (final) и абстрактным (abstract). Поэтому интерфейсы, которые по сути являются абстрактными, не могут быть объявлены как final. Неизменяемый класс и интерфейс представляют две противоположности. Абстрактный класс служит компромиссом между ними.

Java API включает множество неизменяемых классов, например, java.lang.String, который более не может быть специализирован путем определения подклассов.

Если решено, что от класса TubeLight в примере 4.8 нельзя или не следует наследовать, то он может быть определен как final.

final class TubeLight extends Light {
    // Поля
    int tubeLength;

    // Реализация унаследованного абстрактного метода
    public double kwhPrice() { return 2.75; }
}

Таблица 4.3. Свободная таблица модификаторов классов и интерфейсов

Модификаторы Классы Интерфейсы
abstract Может содержать абстрактные методы, не инстанцируетсяНеявно предполагается
final От класса нельзя наследовать Невозможно
Модификаторы доступа для классов и интерфейсов верхнего уровняМодификаторы доступа членов класса