Введение
В этом практическом занятии (лабораторной работе) мы рассмотрим два фундаментальных концепта объектно-ориентированного программирования на Java: наследование и полиморфизм. Эти мощные инструменты позволяют создавать более организованный, эффективный и гибкий код. Сначала мы изучим наследование, которое позволяет создавать новые классы на основе существующих, а затем перейдем к полиморфизму, который позволяет единообразно обрабатывать объекты разных классов.
По завершении этого практического занятия вы сможете:
- Создавать иерархии классов с использованием наследования
- Переопределять методы в подклассах
- Понимать и использовать полиморфизм
- Реализовывать абстрактные классы и методы
Не беспокойтесь, если эти термины звучат сложно – мы разберем все на простые, легко-понимаемые шаги. Давайте начнем наш увлекательный путь к улучшению ваших навыков программирования на Java!
Создание базового класса
Мы начнем с создания базового класса под названием Animal. Этот класс станет основой для наших других классов.
Откройте терминал и перейдите в каталог проекта:
cd ~/projectСоздайте новый файл с именем
Animal.javaс использованием командыtouch:touch Animal.javaОткройте файл
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()), которые позволяют нам получить доступ к приватным атрибутам извне класса.
- Мы определяем класс с именем
Сохраните файл
Animal.java.

Теперь давайте скомпилируем наш класс
Animal, чтобы убедиться, что нет ошибок. В терминале выполните следующую команду:javac Animal.javaЕсли не появилось сообщений об ошибках, значит, ваш класс успешно скомпилирован!
Создание подкласса
Теперь, когда у нас есть базовый класс Animal, давайте создадим подкласс под названием Dog. Это продемонстрирует, как работает наследование в Java.
В вашем терминале создайте новый файл с именем
Dog.java:touch Dog.javaОткройте
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наследуется отAnimal, приватные атрибутыnameиageвAnimalнедоступны напрямую вDog. ОднакоDogможет получить доступ к этим атрибутам через унаследованные публичные методы-геттерыgetName()иgetAge().- Мы добавили новый атрибут
breed, который специфичен дляDog. - Конструктор принимает три параметра. Он использует
super(name, age)для вызова конструктораAnimal, затем устанавливаетbreed. - Мы добавили новый метод
getBreed(), который специфичен дляDog.
Сохраните файл
Dog.java.Скомпилируйте класс
Dog:javac Dog.javaВы можете увидеть предупреждение о Animal.class, но это нормально на данный момент.
Демонстрация наследования
Теперь, когда у нас есть классы Animal и Dog, давайте создадим программу, которая продемонстрирует, как работает наследование.
Создайте новый файл с именем
InheritanceDemo.java:touch 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 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.Сохраните файл
InheritanceDemo.java.Скомпилируйте и запустите программу:
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) — это возможность, которая позволяет подклассу предоставить свою собственную реализацию метода, уже определенного в его суперклассе. Давайте посмотрим, как это работает.
Откройте файл
Dog.javaи добавьте следующий метод:@Override public void eat() { System.out.println(getName() + " is eating dog food."); }Добавьте этот метод внутри класса
Dog, но вне любых других методов.Аннотация
@Overrideсообщает компилятору, что мы намерены переопределить метод из суперкласса. Хотя она не обязательна, использование ее считается хорошей практикой.Сохраните файл
Dog.java.Теперь давайте изменим файл
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()); } }Сохраните файл
InheritanceDemo.java.Скомпилируйте и запустите обновленную программу:
javac Animal.java Dog.java InheritanceDemo.java java InheritanceDemo

Вы должны увидеть вывод, похожий на следующий:
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) — это фундаментальное понятие в объектно-ориентированном программировании, которое позволяет нам использовать ссылку на базовый класс для обращения к объекту подкласса. Это обеспечивает более гибкий и переиспользуемый код. Давайте посмотрим, как это работает.
Создайте новый файл с именем
Cat.java:touch Cat.javaОткройте файл
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().Сохраните файл
Cat.java.Теперь давайте обновим файл
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 автоматически вызывает соответствующую версию метода на основе фактического типа объекта.Сохраните файл
InheritanceDemo.java.Скомпилируйте и запустите обновленную программу:
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:
- Наследование: Мы создали базовый класс
Animalи от него вывели классыDogиCat. Это позволило нам повторно использовать код и создать логическую иерархию классов. - Переопределение методов: Мы увидели, как подклассы могут предоставлять свои собственные реализации методов, определенных в суперклассе, что позволяет реализовать более специфичное поведение.
- Полиморфизм: Мы узнали, как обрабатывать объекты разных классов единообразно через их общий суперкласс, что обеспечивает более гибкий и переиспользуемый код.
Эти концепции являются фундаментальными для Java и объектно-ориентированного программирования в целом. Они позволяют создавать более организованные, эффективные и гибкие структуры кода. По мере продолжения изучения Java вы обнаружите, что эти концепции широко используются в более сложных приложениях.
Помните, что практика - ключ к овладению этими концепциями.



