Наследование и полиморфизм в Java

JavaJavaBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии (лабораторной работе) мы рассмотрим два фундаментальных концепта объектно-ориентированного программирования на Java: наследование и полиморфизм. Эти мощные инструменты позволяют создавать более организованный, эффективный и гибкий код. Сначала мы изучим наследование, которое позволяет создавать новые классы на основе существующих, а затем перейдем к полиморфизму, который позволяет единообразно обрабатывать объекты разных классов.

По завершении этого практического занятия вы сможете:

  1. Создавать иерархии классов с использованием наследования
  2. Переопределять методы в подклассах
  3. Понимать и использовать полиморфизм
  4. Реализовывать абстрактные классы и методы

Не беспокойтесь, если эти термины звучат сложно – мы разберем все на простые, легко-понимаемые шаги. Давайте начнем наш увлекательный путь к улучшению ваших навыков программирования на Java!


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java(("Java")) -.-> java/DataStructuresGroup(["Data Structures"]) java(("Java")) -.-> java/ProgrammingTechniquesGroup(["Programming Techniques"]) java/DataStructuresGroup -.-> java/arrays("Arrays") java/ProgrammingTechniquesGroup -.-> java/method_overriding("Method Overriding") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/classes_objects("Classes/Objects") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/class_attributes("Class Attributes") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/class_methods("Class Methods") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/oop("OOP") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/inheritance("Inheritance") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/polymorphism("Polymorphism") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/annotation("Annotation") subgraph Lab Skills java/arrays -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/method_overriding -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/classes_objects -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/class_attributes -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/class_methods -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/oop -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/inheritance -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/polymorphism -.-> lab-413825{{"Наследование и полиморфизм в Java"}} java/annotation -.-> lab-413825{{"Наследование и полиморфизм в Java"}} end

Создание базового класса

Мы начнем с создания базового класса под названием Animal. Этот класс станет основой для наших других классов.

  1. Откройте терминал и перейдите в каталог проекта:

    cd ~/project
  2. Создайте новый файл с именем Animal.java с использованием команды touch:

    touch Animal.java
  3. Откройте файл Animal.java в текстовом редакторе и добавьте следующий код:

    public class Animal {
        private String name;
        private int age;
    
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void eat() {
            System.out.println(name + " is eating.");
        }
    
        public void sleep() {
            System.out.println(name + " is sleeping.");
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }

    Разберем этот код:

    • Мы определяем класс с именем Animal с двумя атрибутами: name (строка) и age (целое число).
    • Ключевое слово private означает, что эти атрибуты могут быть доступны только внутри класса.
    • У нас есть конструктор, который инициализирует эти атрибуты при создании объекта Animal.
    • У нас есть два метода: eat() и sleep(), которые выводят, что животное делает.
    • Также у нас есть методы "геттеры" (getName() и getAge()), которые позволяют нам получить доступ к приватным атрибутам извне класса.
  4. Сохраните файл Animal.java.

Saving Animal java file
  1. Теперь давайте скомпилируем наш класс Animal, чтобы убедиться, что нет ошибок. В терминале выполните следующую команду:

    javac Animal.java

    Если не появилось сообщений об ошибках, значит, ваш класс успешно скомпилирован!

Создание подкласса

Теперь, когда у нас есть базовый класс Animal, давайте создадим подкласс с именем Dog. Это продемонстрирует, как работает наследование в Java.

  1. В терминале создайте новый файл с именем Dog.java:

    touch Dog.java
  2. Откройте файл Dog.java в текстовом редакторе и добавьте следующий код:

    public class Dog extends Animal {
        private String breed;
    
        public Dog(String name, int age, String breed) {
            super(name, age);  // Call the superclass constructor
            this.breed = breed;
        }
    
        public String getBreed() {
            return breed;
        }
    }

    Разберем этот новый код:

    • extends Animal сообщает Java, что Dog является подклассом Animal. Это означает, что Dog наследует все нечастные (не private) методы и атрибуты от Animal.
    • Мы добавили новый атрибут breed, который специфичен для Dog.
    • Конструктор принимает три параметра. Он использует super(name, age) для вызова конструктора Animal, а затем устанавливает значение breed.
    • Мы добавили новый метод getBreed(), который специфичен для Dog.
  3. Сохраните файл Dog.java.

  4. Скомпилируйте класс Dog:

    javac Dog.java

    Возможно, вы увидите предупреждение о Animal.class, но это сейчас не критично.

Демонстрация наследования

Теперь, когда у нас есть классы Animal и Dog, давайте создадим программу, которая продемонстрирует, как работает наследование.

  1. Создайте новый файл с именем InheritanceDemo.java:

    touch InheritanceDemo.java
  2. Откройте файл InheritanceDemo.java и добавьте следующий код:

    public class InheritanceDemo {
        public static void main(String[] args) {
            Animal genericAnimal = new Animal("Generic Animal", 5);
            Dog myDog = new Dog("Buddy", 3, "Labrador");
    
            System.out.println("Demonstrating Animal class:");
            genericAnimal.eat();
            genericAnimal.sleep();
    
            System.out.println("\nDemonstrating Dog class:");
            myDog.eat();  // Inherited from Animal
            myDog.sleep();  // Inherited from Animal
    
            System.out.println("\nDog details:");
            System.out.println("Name: " + myDog.getName());  // Inherited method
            System.out.println("Age: " + myDog.getAge());  // Inherited method
            System.out.println("Breed: " + myDog.getBreed());  // Dog-specific method
        }
    }

    Эта программа создает экземпляры как класса Animal, так и класса Dog и демонстрирует, как класс Dog наследует методы от класса Animal.

  3. Сохраните файл InheritanceDemo.java.

  4. Скомпилируйте и запустите программу:

    javac InheritanceDemo.java
    java InheritanceDemo

    Вы должны увидеть вывод, похожий на следующий:

    Demonstrating Animal class:
    Generic Animal is eating.
    Generic Animal is sleeping.
    
    Demonstrating Dog class:
    Buddy is eating.
    Buddy is sleeping.
    
    Dog details:
    Name: Buddy
    Age: 3
    Breed: Labrador

Эта демонстрация показывает, как класс Dog наследует атрибуты и методы от класса Animal, при этом добавляя свои собственные специфические атрибут (breed) и метод (getBreed()).

Переопределение методов

Переопределение методов (method overriding) — это возможность, которая позволяет подклассу предоставить свою собственную реализацию метода, уже определенного в его суперклассе. Давайте посмотрим, как это работает.

  1. Откройте файл Dog.java и добавьте следующий метод:

    @Override
    public void eat() {
        System.out.println(getName() + " is eating dog food.");
    }

    Добавьте этот метод внутри класса Dog, но вне любых других методов.

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

  2. Сохраните файл Dog.java.

  3. Теперь давайте изменим файл InheritanceDemo.java, чтобы продемонстрировать переопределение методов. Откройте InheritanceDemo.java и замените его содержимое на следующее:

    public class InheritanceDemo {
        public static void main(String[] args) {
            Animal genericAnimal = new Animal("Generic Animal", 5);
            Dog myDog = new Dog("Buddy", 3, "Labrador");
    
            System.out.println("Demonstrating method overriding:");
            genericAnimal.eat();
            myDog.eat();
    
            System.out.println("\nDemonstrating inherited method:");
            myDog.sleep();  // This method is still inherited from Animal
    
            System.out.println("\nDog details:");
            System.out.println("Name: " + myDog.getName());
            System.out.println("Age: " + myDog.getAge());
            System.out.println("Breed: " + myDog.getBreed());
        }
    }
  4. Сохраните файл InheritanceDemo.java.

  5. Скомпилируйте и запустите обновленную программу:

    javac Animal.java Dog.java InheritanceDemo.java
    java InheritanceDemo
Method overriding output example

Вы должны увидеть вывод, похожий на следующий:

Demonstrating method overriding:
Generic Animal is eating.
Buddy is eating dog food.

Demonstrating inherited method:
Buddy is sleeping.

Dog details:
Name: Buddy
Age: 3
Breed: Labrador

Это демонстрирует, как переопределение методов позволяет классу Dog предоставить свою собственную реализацию метода eat(), при этом по-прежнему наследуя другие методы, такие как sleep(), от класса Animal.

Введение в полиморфизм

Полиморфизм (polymorphism) — это фундаментальное понятие в объектно-ориентированном программировании, которое позволяет нам использовать ссылку на базовый класс для обращения к объекту подкласса. Это обеспечивает более гибкий и переиспользуемый код. Давайте посмотрим, как это работает.

  1. Создайте новый файл с именем Cat.java:

    touch Cat.java
  2. Откройте файл Cat.java и добавьте следующий код:

    public class Cat extends Animal {
        public Cat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println(getName() + " is eating fish.");
        }
    
        public void meow() {
            System.out.println(getName() + " says: Meow!");
        }
    }

    Это создает еще один подкласс Animal с собственным методом eat() и новым методом meow().

  3. Сохраните файл Cat.java.

  4. Теперь давайте обновим файл InheritanceDemo.java, чтобы продемонстрировать полиморфизм. Замените его содержимое на следующее:

    public class InheritanceDemo {
        public static void main(String[] args) {
            Animal[] animals = new Animal[3];
            animals[0] = new Animal("Generic Animal", 5);
            animals[1] = new Dog("Buddy", 3, "Labrador");
            animals[2] = new Cat("Whiskers", 2);
    
            System.out.println("Demonstrating polymorphism:");
            for (Animal animal : animals) {
                animal.eat();  // This will call the appropriate eat() method for each animal
            }
    
            System.out.println("\nAccessing specific methods:");
            ((Dog) animals[1]).getBreed();  // We need to cast to Dog to call Dog-specific methods
            ((Cat) animals[2]).meow();      // We need to cast to Cat to call Cat-specific methods
        }
    }

    Этот код создает массив объектов Animal, но на самом деле в нем хранится смесь объектов Animal, Dog и Cat. Когда мы вызываем метод eat() для каждого животного, Java автоматически вызывает соответствующую версию метода на основе фактического типа объекта.

  5. Сохраните файл InheritanceDemo.java.

  6. Скомпилируйте и запустите обновленную программу:

    javac Animal.java Dog.java Cat.java InheritanceDemo.java
    java InheritanceDemo

    Вы должны увидеть вывод, похожий на следующий:

    Demonstrating polymorphism:
    Generic Animal is eating.
    Buddy is eating dog food.
    Whiskers is eating fish.
    
    Accessing specific methods:
    Whiskers says: Meow!

Это демонстрирует работу полиморфизма. Мы можем рассматривать все объекты как объекты класса Animal, но когда мы вызываем метод eat(), каждый объект ведет себя в соответствии с реализацией метода в своем конкретном классе.

Резюме

В этом практическом занятии мы изучили некоторые ключевые концепции объектно-ориентированного программирования на Java:

  1. Наследование: Мы создали базовый класс Animal и от него вывели классы Dog и Cat. Это позволило нам повторно использовать код и создать логическую иерархию классов.
  2. Переопределение методов: Мы увидели, как подклассы могут предоставлять свои собственные реализации методов, определенных в суперклассе, что позволяет реализовать более специфичное поведение.
  3. Полиморфизм: Мы узнали, как обрабатывать объекты разных классов единообразно через их общий суперкласс, что обеспечивает более гибкий и переиспользуемый код.

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

Помните, что практика - ключ к овладению этими концепциями.