yandex rtb 1
ГоловнаЗворотній зв'язок
yande share

Объектно-ориентированное программирование

Лекция 13.

Наследование в языке Java. Класс Object.  Абстрактные методы и классы. Финальные методы и классы.

 

Рассмотрим, как реализованы в языке принципы наследования. Опишем, например, класс WeightCube, являющийся подклассом класса Cube из предыдущей лекции.

 

class WeightCube extends Cube {

double weight;

WeightCube(double length, double weight) {

      super(length);

      this.weight=weight;

}

WeightCube() {

      super();

      weight=1;

}

public void show() {

System.out.println("length="+length+" volume="+super.volume()+" weight="+weight);

}

public static void main(String args[]) {

Cube c1;

c1=new Cube();

Cube c;

c=c1;

c.show();

WeightCube w1=new WeightCube(1.25,2);

c=w1;

c.show();

}

}

 

Данный класс является подклассом класса Cube. Об этом свидетельствует ключевое слово extends после имени определяемого класса WeightCube. В конструкторах подкласса мы используем конструктор суперкласса. Нет необходимости вызывать конструктор суперкласса по имени – это делается с помощью ключевого слова super. Это возможно, потому то язык Java не допускает множественного наследования – подкласс имеет только одного родителя (разумеется, родитель может в свою очередь иметь своего родителя и т.д.).

Класс WeightCube мы дополнили одной переменной weight стандартного типа double. Мы не определили права доступа к этой переменной. Язык Java может это сделать за нас, определив права доступа по умолчанию. В классе переопределен метод show суперкласса. Этот метод будет работать правильно только в том случае, если переменная length в суперклассе определена с методом доступа protected (или public), т.е. закрытым для всех, кроме методов подкласса. Если переменная length останется с методом доступа private, как это было определено ранее, программа окажется неработоспособной.

Методы подкласса могут использовать не только открытые и защищенные переменные суперкласса, но и открытые и защищенные методы. Например, для переопределенного в подклассе метода show показан вызов метода суперкласса volume. Для вызова метода суперкласса здесь использовалось уточнение с помощью ключевого слова super. В данном случае это не имеет никакого значения. так как мы не переопределяли этот метод в подклассе. Но в общем случае с помощью такой конструкции в подклассе можно выбрать - какой метод должен применяться.

 Заметим, что в языке Java решение о применимости переопределенного метода принимается не на этапе компиляции, а на этапе выполнения (т.е. фактически все методы в языке Java являются виртуальными). Это называется динамической диспетчеризацией методов. Ее демонстрирует метод main. В языке Java ссылочная переменная суперкласса может обращаться к объекту подкласса. Поэтому в данном примере ссылочная переменная c сначала обращается к методу show класса Cube (так как ссылается на объект этого класса), а потом – к тому же методу класса WeightCube (переменная c ссылается уже на объект данного класса).

Для класса Cube мы не указывали никакого суперкласса. Но это не значит, что он стоит на вершине иерархии. На самом деле, если не пишется имя суперкласс, он считается унаследованным от стандартного класса Object, который и стоит в вершине иерархии классов языка Java. Поэтому все классы содержат некоторые стандартные методы:

equals – позволяет сравнивать два объекта;

toString – преобразует содержание класса в строку.

Желательно в своем собственном классе переопределять эти методы, так как стандартная реализация этих методов не всегда приводит к нужным результатам. Например, мы можем для класса WeightCube переопределить этот метод следующим образом:

 

public String toString() {

return "length="+length+" volume="+super.volume()+" weight="+weight;

}

 

При этом уже не возникнет необходимости в методе show. Вывод в виде:

System.out.println(c);

даст точно такой же эффект.

Язык Java поддерживает также концепцию абстрактных классов. В ситуации, когда необходимо лишь определить структуру некоторой абстракции без законченной реализации всех методов, мы можем определить класс как абстрактный. При этом нереализованные методы также объявляются как абстрактные. Мы лишь определяем их природу. Невозможно создать объекты абстрактного класса. Мы можем лишь использовать его как суперкласс для некоторых других классов. При этом в подклассах, созданных на основе абстрактного суперкласса, должны быть переопределены все абстрактные методы. Пример определения абстрактного класса и созданного на его основе подкласса показан ниже.

abstract class Shape {

protected double dim1;

protected double dim2;

abstract public double area();

Shape(double d1, double d2) {

dim1=d1;

dim2=d2;

}

}

class Rectangle extends Shape {

Rectangle(double width, double height) {

super(width,height);

}

public double area() {

return dim1*dim2;

}

}

Мы определили абстрактный класс Shape. Он содержит две защищенные переменные dim1 и dim2 и конструктор класса. Также абстрактный класс содержит абстрактный метод area, который должен быть переопределен в подклассе. Подкласс Rectangle класса Shape имеет конструктор, использующий конструктор суперкласса, а также переопределенный метод area, подсчитывающий площадь прямоугольника. Разумеется, класс Rectangle может содержать и другие методы, не определенные в суперклассе.

Язык Java позволяет не только создавать иерархию классов, но и запрещать в некоторых случаях создавать иерархию и переопределять методы. Делается это с помощью ключевого слова final. Метод, помеченный этим ключевым словом, не может быть переопределен в подклассе. Например, в классе Rectangle таким образом мы могли бы пометить метод area:

public final double area() …

Теперь мы можем быть уверены, что ни в каком подклассе этот метод не может быть изменен – ведь метод вычисления площади прямоугольника остается тем же. Это может быть использовано для большей безопасности программ.

Таким же образом мы можем запретить расширение всего класса. Для этого достаточно также описать его как final. Подкласс на основе такого класса создать уже невозможно. Это полезно, если, например, класс инкапсулирует какие-либо расчетные методы, которые не должны быть изменены. Например, стандартный класс Math в языке Java объявлен как final – было бы странно иметь возможность самому переопределить математические функции.

Этим же модификатором могут быть помечены переменные. В этом случае изменить эти переменные невозможно – они превращаются по существу в константы, которые обычно записываются прописными буквами:

public final int MIN_VALUE=0;

 

15