Философия Java

Синтаксис наследования


Наследование является неотъемлемой частью Java, впрочем, как и других ОО языков программирования. Это очевидно - Вы всегда осуществляете операцию наследования, когда создаете класс, даже если ваш класс не является наследником какого либо другого, потому, что Вы неявно наследуете стандартный корневой класс Java Object.

Синтаксис наследования похож на композицию, но процедура выполнения заметно отличается. Когда Вы наследуете, Вы "говорите": "Этот класс такой же, как тот старый класс!" Вы излагаете эту фразу в коде давая классу имя, как обычно, но до того, как начнете работать с телом класса, добавляете ключевое слово extends следующее до имени базового класса. Когда вы сделаете это, вы автоматически получите все поля данных и методы базового класса. Вот пример:

//: c06:Detergent.java

// Свойства и синтаксис наследования.

class Cleanser { private String s = new String("Cleanser"); public void append(String a) { s += a; } public void dilute() { append(" dilute()"); } public void apply() { append(" apply()"); } public void scrub() { append(" scrub()"); } public void print() { System.out.println(s); } public static void main(String[] args) { Cleanser x = new Cleanser(); x.dilute(); x.apply(); x.scrub(); x.print(); } }

public class Detergent extends Cleanser { // Изменяем метод:

public void scrub() { append(" Detergent.scrub()"); super.scrub(); // Вызываем метод базового класса

} // Все методы наследования:

public void foam() { append(" foam()"); } // Проверяем новый класс:

public static void main(String[] args) { Detergent x = new Detergent(); x.dilute(); x.apply(); x.scrub(); x.foam(); x.print(); System.out.println("Testing base class:"); Cleanser.main(args); } } ///:~

Этот пример показывает несколько возможностей. Сперва в методе Cleanser append( ) , String-и конкатенируются с s при помощи оператора "+=", это один из операторов (с плюсом впереди), который перегружается Java для работы с типом String.


Во-вторых, оба Cleanser и Detergent содержат метод main( ). Вы можете создать main( ) для каждого из ваших классов и часто рекомендуется писать такой код для тестирования каждого из классов. Если же у Вас имеется множество классов в программе, то выполнится только метод main( ) того класса, который был вызван из командной стоки. Так что в этом случае, когда вы вызовите java Detergent, будет вызван метод Detergent.main( ) . Но так же вы можете вызвать java Cleanser для выполнения Cleanser.main( ), несмотря даже на то, что класс Cleanser не public . Эта техника помещения метода main( ) в каждый класс позволяет легко проверять каждый из классов программы по отдельности. И Вам нет необходимости удалять main( ) когда вы закончили проверки, Вы можете оставить его для будущих проверок.
Здесь Вы можете видеть, что Detergent.main( ) явно вызывает Cleanser.main( ) , передавая ему те же самые аргументы из командной строки(тем не менее, Вы могли были передать ему любой , массив элементов типа String).
Важно то, что все методы в Cleanser - public. Помните, если Вы оставите любой из спецификаторов доступа в состоянии по умолчанию, т.е. он будет friendly, то доступ к нему могут получить только члены этого же пакета. Поэтому в этом пакете все могут использовать эти методы, если у них нет спецификатора доступа. Detergent с эти проблем не имеет, к примеру. Но в любом случае, если класс из другого пакета попытается наследовать Cleanser он получит доступ только к членам со спецификатором public. Так что если Вы планируете использовать наследование, то в качестве главного правила делайте все поля private и все методы public. (protected так же могут получить доступ к наследуемым классам, но Вы узнаете об этом позже.) Естественно в частных случаях Вы должны делать поправки на эти самые частные случаи, но все равно это полезная линия поведения.
Замете, что Cleanser имеет набор методов из родительского интерфейса: append( ), dilute( ), apply( ), scrub( ), и print( ). Из-за того, что Detergent произошел от Ceanser (при помощи ключевого слова extends ) он автоматически получил все те методы, что есть в его интерфейсе, даже не смотря на то, что вы не видите их определенных в Detergent. Вы можете подумать о наследовании, а уже только затем о повторном использовании интерфейса.


Как видно в scrub( ) , возможно создать метод, который определяется в базовом классе, а затем уже его модифицировать. В таком случае, Вы можете захотеть вызвать метод внутри базового класса этот новый модифицированный метод. Но внутри scrub( ) вы не можете просто вызвать scrub( ), поскольку эта операция вызовет рекурсивный вызов, а это не то, что Вы хотите. Для разрешения этой проблемы в Java используется ключевое слово super , которое ссылается на superclass, который в свою очередь является классом, от которого произошел текущий класс. Поэтому выражение super.scrub( ) вызывает метод базового класса scrub( ).
При наследовании вы не ограничены в использовании методов базового класса. Вы можете так же добавлять новые методы в новый класс. Это сделать очень просто, нужно просто определить их. Метод foam( ) тому демонстрация.
В Detergent.main( ) вы можете увидеть, что у объекта Detergent Вы можете вызвать все методы, которые доступны в Cleanser так же, как и в Detergent (в том числе и foam( )).

Содержание раздела