Java. Наследование. Ссылка на объект подкласса. Вызов конструктора суперкласса. Ключевое слово super

Наследование. Ссылка на объект подкласса. Вызов конструктора суперкласса. Ключевое слово super


Содержание


1. Можно ли ссылке на суперкласс присвоить ссылку на объект подкласса?

Да, можно. Пусть заданы суперкласс и подкласс. Если объявить ссылку на суперкласс, то этой ссылке можно присвоить значение ссылки на подкласс, который наследует этот суперкласс.

Например. Даны два класса A и B. Класс A есть суперклассом (базовым классом). Класс B есть подклассом класса A.

// класс A - суперкласс для класса B
class A {
    int a; // внутренняя переменная
}

// класс B - подкласс класса A
class B extends A {
    int b;
}

Тогда, в другом методе можно объявить ссылку на класс A и присвоить этой ссылке значение экземпляра класса B

// ссылка на класс A может ссылаться на класс B
A objA = new A(); // экземпляр (объект) класса A
B objB = new B(); // экземпляр (объект) класса B
A rA; // ссылка на класс A

// ссылке на класс A присваивается ссылка на экземпляр класса B
rA = objB;

rA.a = 30; // так можно, rA.a = 30
// rA.b = 20; // ошибка, запрещено

rA = objA; // так тоже можно, однако rA.a = 0

В случае, когда ссылке на суперкласс rA присваивается ссылка на объект подкласса objB доступными для ссылки rA являются члены класса A, для которого была объявлена эта ссылка. В данном случае ссылке rA доступен член класса A с именем a. Члены класса B есть недоступными для ссылки rA.

Вывод: для ссылки на суперкласс доступные члены класса определяются типом ссылки, а не типом объекта на который эта ссылка ссылается.

Если с помощью ссылки rA попробовать доступиться к члену данных b класса B

r.b = 20; // это ошибка!

то компилятор выдаст ошибку

b cannot be resolved or is not a field

 

2. Можно ли ссылке на подкласс присвоить ссылку на объект суперкласса?

Нет, нельзя. Суперкласс не может расширяться до возможностей подкласса. Это противоречит парадигме наследственности. Наоборот, подкласс, который расширяет возможности суперкласса, может «суживаться» к суперклассу.

Например. Пусть заданы два класса A и B. Класс A есть суперклассом (базовым классом). Класс B есть подклассом класса A.

// класс A - суперкласс для класса B
class A {
    int a; // внутренняя переменная
}

// класс B - подкласс класса A
class B extends A {
    int b;
}

Попытка присвоить ссылке на класс B значение ссылки на класс A

A objA = new A(); // objA - ссылка на экземпляр класса A
B rB; // ссылка на подкласс B

// суперкласс A не может быть приведен к классу B
rB = (B)objA; // ошибка!

приведет к возникновению критической ситуации с сообщением

A cannot be cast to B

 

3. Какие существуют формы использования ключевого слова super?

Существуют две формы использования ключевого слова super:

  • для вызова конструктора суперкласса;
  • для доступа к члену суперкласса из подкласса. Такой доступ нужен в ситуациях, когда имя члена подкласса совпадает с именем члена суперкласса, к которому нужно доступиться из подкласса. В этом случае имя члена данных подкласса перекрывает имя суперкласса.

 

4. Как осуществляется вызов из подкласса конструктора суперкласса? Ключевое слово super. Общая форма

Конструктор суперкласса (базового класса) может быть вызван из подкласса (производного класса). Этот вызов осуществляется с помощью ключевого слова super. Вызов конструктора суперкласса должен быть осуществлен в теле конструктора подкласса первым.

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

super(parameters);

здесь

  • parameters – перечень параметров, которые получает конструктор. Если конструктор не имеет параметров, то конструктор суперкласса вызывается как super().


 

5. Примеры вызова конструкторов суперкласса из подкласса

Пример 1. Задан класс Point, описывающий точку на плоскости. Класс расширяется подклассом ColorPoint, который добавляет свойство цвет к точке.

Реализация классов Point и ColorPoint следующая

// класс, который описывает точку на плоскости
class Point {
    // координаты точки
    private double x;
    private double y;

    // конструктор класса
    public Point()
    {
        x = y = 0;
    }

    public Point(double _x, double _y) {
        x = _x;
        y = _y;
    }

    // методы доступа
    // взять точку
    public Point GetP() {
        return this;
    }

    // установить новое значение точки
    public void SetP(Point np) {
        x = np.x;
        y = np.y;
    }

    public double GetX() { return x; }
    public double GetY() { return y; }
}

// класс точка с цветом - расширяет возможности Point
class ColorPoint extends Point {
    private double color;

    // конструкторы класса ColorPoint
    ColorPoint() {
        // вызвать конструктор без параметров суперкласса Point
        super();
        color = 0;
    }

    ColorPoint(double _x, double _y, double _c) {
        // вызвать конструктор с двумя параметрами класса Point
        super(_x,_y);
        color = _c;
    }

    // установить новое значение ColorPoint
    void SetCP(double _x, double _y, double _c) {
        // super(_x,_y); // запрещено вызывать конструктор из метода
        Point p = new Point(_x,_y); // создать объект класса Point
        SetP(p); // установить новое значение координат точки
        color = _c;
    }

    // взять цвет
    public double GetColor() {
        return color;
    }
}

В вышеприведенном коде, в конструкторах подкласса ColorPoint вызывается конструктор класса Point с помощью ключевого слова super

...
// конструкторы класса ColorPoint
ColorPoint() {
    // вызвать конструктор без параметров суперкласса Point
    super();
    color = 0;
}

ColorPoint(double _x, double _y, double _c) {
    // вызвать конструктор с двумя параметрами класса Point
    super(_x,_y);
    color = _c;
}
...

Пример 2. Вызов конструктора суперкласса в случае многоуровневой наследственности. В примере объявляется 4 класса с именами A1, A2, A3, A4. Класс A1 есть суперклассом для класса A2. Класс A2 есть суперклассом для класса A3. Класс A3 есть суперклассом для класса A4.

Ниже приведен программный код, демонстрирующий использование ключевого слова super и многоуровневой наследственности

// суперкласс
class A1 {
    A1() {
        System.out.println("A1");
    }
}

// подкласс класса A1
class A2 extends A1 {
    A2() {
        super();
        System.out.println("A2");
    }
}

// подкласс класса A2
class A3 extends A2 {
    A3() {
        super();
        System.out.println("A3");
    }
}

// подкласс класса A3
class A4 extends A3 {
    A4() {
        super();
        System.out.println("A4");
    }
}

Если создать экземпляр класса A4

A4 objA4 = new A4();

то будет выведен следующий результат

A1
A2
A3
A4

В вышеприведенном примере класс A2 наследует все характеристики класса A1. Класс A3 наследует все характеристики классов A1, A2. Класс A4 наследует все характеристики классов A1, A2, A3.

 

6. Какие требования относятся к вызову конструктора суперкласса с помощью ключевого слова super?

К вызову конструктора суперкласса с помощью ключевого слова super относятся следующие требования:

  • конструктор суперкласса может быть вызван только из конструктора подкласса;
  • вызов констуктора суперкласса должно быть первым в конструкторе подкласса;
  • вызвать конструктор суперкласса из любого метода подкласса (кроме конструктора) запрещено.

 

7. Можно ли вызвать конструктор суперкласса из любого метода подкласса с помощью вызова super?

Нет, нельзя. Если в некотором методе подкласса попробовать вызвать конструктор суперкласса с помощью ключевого слова super(), то компилятор Java выдаст ошибку:

Constructor call must be the first statement in a constructor

 

8. Пример доступа к члену суперкласса из подкласса с использованием ключевого слова super

Ключевое слово super используется для доступа к члену суперкласса в случае, если в подклассе используется точно такое же имя.

// доступ к члену суперкласса с помощью слова super
class A {
    double x = 2.5;
}

class B extends A {
    double x = 5.0; // переменная x класса A
}

class C extends B {
    double x = super.x; // x = 5.0 - переменная x класса B
}

В вышеприведенном примере член x класса C инициализируется значением x класса B с помощью обращения:

super.x

 

9. Каким образом осуществляется порядок вызова конструкторов в случае наследования? Пример

Если два и более класса образуют иерархию наследования, то конструкторы вызываются в направлении от наивысшего класса в иерархии (от суперкласса) к низшему (к подклассу наиболее низкого уровня).

Например. Заданы 4 класса с именами A, B, C, D. Класс A есть суперклассом для класса B. Класс B есть суперклассом для класса C. Класс C есть суперклассом для класса D.

// класс A - наивысший класс в иерархии
class A {  
    // конструктор класса A
    A() {
        System.out.println("The constructor of class A.");
    }
}

// класс B есть подклассом класса A
class B extends A {
    // конструктор класса B
    B() {
        System.out.println("The constructor of class B.");
    }
}

//класс C есть подклассом класса B
class C extends B {
    // конструктор класса C
    C() {
        System.out.println("The constructor of class C.");
    }
}

//класс C есть подклассом класса D
class D extends C {
    // конструктор класса D
    D() {
        System.out.println("The constructor of class D.");      
    }
}

public class Train01 {

    public static void main(String[] args) {
        // создать объект класса D
        D obj = new D(); // конструкторы вызываются в порядке A(), B(), C(), D()        
    }
}

В вышеприведенном примере при объявлении объекта класса D

D obj = new D(); // конструкторы вызываются в порядке A(), B(), C(), D()

конструкторы вызываются в порядке

A()
B()
C()
D()

Результат выполнения программы

The constructor of class A.
The constructor of class B.
The constructor of class C.
The constructor of class D.

 


Связанные темы