Наследование в Java

Наследование — это механизм, при котором один класс (подкласс, child) получает поля и методы другого класса (суперкласс, parent) и может добавлять к ним свои или переопределять унаследованные. Так строится иерархия типов: например, LedRgb — это разновидность Led, а Led — разновидность Device.

Главная цель наследования — переиспользование кода и моделирование отношения «является» (is-a). Если B наследник A, то любой объект B является объектом A, и ссылка типа A может указывать на объект B.

В Java множественное наследование классов запрещено: у класса есть только один прямой суперкласс. Если extends не указан, неявно наследуется java.lang.Object.

Синтаксис

class Parent {
    // ...
}

class Child extends Parent {
    // дополнительные поля/методы
}

Внутри подкласса доступно ключевое слово super — ссылка на «родительскую часть» объекта, обычно используется для вызова конструктора или переопределённого метода суперкласса.

Пример 1. Базовое наследование

class Device {
    String name;

    void info() {
        System.out.println("Device: " + name);
    }
}

public class Led extends Device {
    int pin;

    public static void main(String[] args) {
        Led led = new Led();
        led.name = "LED1";
        led.pin = 13;
        led.info();                // унаследовано
        System.out.println("pin=" + led.pin);
    }
}

Output:

Device: LED1
pin=13

Пример 2. Конструкторы и super(…)

class Device {
    String name;

    Device(String name) {
        this.name = name;
        System.out.println("Device(" + name + ")");
    }
}

public class Sensor extends Device {
    int pin;

    Sensor(String name, int pin) {
        super(name);
        this.pin = pin;
        System.out.println("Sensor(" + name + ", " + pin + ")");
    }

    public static void main(String[] args) {
        new Sensor("DHT22", 4);
    }
}

Output:

Device(DHT22)
Sensor(DHT22, 4)

Пример 3. Переопределение метода

class Device {
    String name = "Generic";

    void info() {
        System.out.println("Это устройство: " + name);
    }
}

public class Motor extends Device {
    int speed = 0;

    @Override
    void info() {
        System.out.println("Мотор " + name + ", скорость " + speed);
    }

    public static void main(String[] args) {
        Device a = new Device();
        Motor b = new Motor();
        b.name = "Левый";
        b.speed = 120;
        a.info();
        b.info();
    }
}

Output:

Это устройство: Generic
Мотор Левый, скорость 120

Пример 4. Вызов родительской реализации через super

class Device {
    String name = "X";

    void info() {
        System.out.println("[Device] " + name);
    }
}

public class Sensor extends Device {
    int pin = 7;

    @Override
    void info() {
        super.info();              // выводит "[Device] X"
        System.out.println("[Sensor] pin=" + pin);
    }

    public static void main(String[] args) {
        new Sensor().info();
    }
}

Output:

[Device] X
[Sensor] pin=7

Пример 5. Полиморфизм ссылок

class Device {
    void hello() {
        System.out.println("hello from Device");
    }
}

class Led extends Device {
    @Override
    void hello() {
        System.out.println("hello from Led");
    }
}

public class Motor extends Device {
    @Override
    void hello() {
        System.out.println("hello from Motor");
    }

    public static void main(String[] args) {
        Device[] devs = { new Device(), new Led(), new Motor() };
        for (Device d : devs) {
            d.hello();   // вызовется метод фактического класса
        }
    }
}

Output:

hello from Device
hello from Led
hello from Motor

Пример 6. Иерархия из трёх уровней

class Device {
    void on()  { System.out.println("Device.on"); }
    void off() { System.out.println("Device.off"); }
}

class Light extends Device {
    void blink() { System.out.println("Light.blink"); }
}

public class Rgb extends Light {
    void color(String c) { System.out.println("Rgb.color=" + c); }

    public static void main(String[] args) {
        Rgb rgb = new Rgb();
        rgb.on();          // из Device
        rgb.blink();       // из Light
        rgb.color("red");  // из Rgb
    }
}

Output:

Device.on
Light.blink
Rgb.color=red

Подводные камни

  • private поля и методы суперкласса не доступны в подклассе напрямую — только через публичные/protected методы.

  • super(...) (вызов конструктора родителя) должен быть первой строкой конструктора. Если его нет — Java неявно вставит super(); (без параметров).

  • Аннотация @Override — не обязательна, но рекомендуется: компилятор сообщит, если вы случайно сделали не переопределение, а перегрузку.

  • Поля не «переопределяются» — они скрываются. При обращении a.field через ссылку типа A вы получите поле A, даже если объект на самом деле — B.

  • Java не поддерживает множественного наследования классов. Если нужно «много родителей» — используют интерфейсы.

  • Класс с модификатором final нельзя наследовать; метод с final нельзя переопределить.

См. также

Примечание

Лицензия и источники

Концепция описана на основе официального Java Tutorial от Oracle (https://docs.oracle.com/javase/tutorial/), Oracle Free Documentation License. Перевод, примеры и пояснения — © AlashEd Wiki.