Топ-100Полиморфизм в Java
LogoCodOrbits

Раздел: ООП

Здесь вы познакомитесь с объектно-ориентированным программированием в Java: классы, наследование, инкапсуляция и полиморфизм и многое другое.

Все разделы
Иконка ООП

Полиморфизм в Java

Last updated: 3 мая 2025 г.

Полиморфизм — возможность использовать одно и то же имя для разных реализаций методов или конструкторов.

В Java полиморфизм реализуется с помощью перегрузки (overloading) и переопределения (overriding).

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

Возникает закономерный вопрос: когда мы воспользуемся одним из таких методов с одинаковым именем, как компилятор определяет, какую реализацию выбрать? Ответ прост — он делает это на основании числа и типов переданных аргументов.

Рассмотрим пример перегрузки конструкторов:

1class Animal {
2    private String eats;
3    private int noOfLegs;
4
5    //Конструктор без параметров
6    //(называется конструктором по умолчанию).
7    public Animal(){}
8
9    //Конструктор с одним параметром
10    //задает значение только полю eats.
11    public Animal(String food){
12        this.eats = food;
13    }
14
15    //Конструктор с несколькими параметрами
16    //задает значения обоим полям.
17    public Animal(String food, int legs){
18        this.eats = food;
19        this.noOfLegs = legs;
20    }
21
22    //сеттеры и геттеры
23    public String getEats() {
24        return eats;
25    }
26
27    public void setEats(String eats) {
28        this.eats = eats;
29    }
30
31    public int getNoOfLegs() {
32        return noOfLegs;
33    }
34
35    public void setNoOfLegs(int noOfLegs) {
36        this.noOfLegs = noOfLegs;
37    }
38}
39
40class Polimorphism {
41    public static void main(String[] args) {
42        //Какой же из конструкторов
43        //Animal, которые мы определили будет использован
44        //при создании объекта животного?
45        //Ведь у них же всех одинаковые имена.
46
47        //На самом деле, можно просто выбрать
48        //нужный конструктор передав в него 
49        //нужное количество параметров.
50        //То есть, как видим, в строке кода ниже
51        //вызывается конструктор с одним параметром.
52        Animal animal = new Animal("Grass");
53        //Значит будет использован конструктор
54        //public Animal(String food), ведь в конструктор 
55        //передаётся всего один параметр.
56
57        //В выводе увидим, что строка Grass успешно
58        //записалась в поле объекта animal.
59        System.out.println(animal.getEats());
60    }
61}

Вывод:

Даже несмотря на то, что у всех конструкторов одинаковое имя Animal, компилятор различает их по параметрам. Это и есть пример перегрузки конструктора, которая является одной из форм полиморфизма.

Однако помним, что полиморфизм может применяться не только к конструкторам, но и к методам.


Переопределение метода родителя в классе-наследнике

Под полиморфизмом также понимается переопределение метода родительского класса в классе-наследнике.

Например, ниже в классе Animal (Животное) определён метод move() (Движение), который просто сообщает, что животное может двигаться. Его реализация — вывод строки "The animal moves." — является универсальной и подходит для любого животного. Такой метод вполне может использоваться без изменений в классах-наследниках.

Однако в некоторых случаях желательно уточнить поведение метода. Например, если мы создадим класс Cat (Кот), который наследуется от Animal, то он унаследует и метод move(). Но в контексте кошки может быть полезно уточнить поведение этого метода, поскольку, разумеется, куда лучше, если move() будет описывать именно движения, характерные для кошки — например, "The cat gracefully walks and jumps." — а не просто общее "The animal moves."

В таких случаях метод move() можно переопределить в классе-наследнике, чтобы сделать поведение более конкретным и реалистичным.

Это и есть проявление полиморфизма: один и тот же метод, но разная реализация в разных классах.

Рассмотрим пример:

1class Animal {
2    private String eats;
3    private int noOfLegs;
4
5    public Animal(){}
6    public Animal(String food){
7        this.eats = food;
8    }
9    public Animal(String food, int legs){
10        this.eats = food;
11        this.noOfLegs = legs;
12    }
13
14    public String getEats() {
15        return eats;
16    }
17
18    public void setEats(String eats) {
19        this.eats = eats;
20    }
21
22    public int getNoOfLegs() {
23        return noOfLegs;
24    }
25
26    public void setNoOfLegs(int noOfLegs) {
27        this.noOfLegs = noOfLegs;
28    }
29    // Метод с базовой реализацией, который,
30    // желательно, чтобы наследники переопределили.
31    public void move() {
32        System.out.println("The animal moves.");
33    }
34}
35
36class Cat extends Animal{
37    private String name;
38    private String color;
39
40    Cat(){}
41    Cat (String catName, String catColor) {
42        name = catName;
43        color = catColor;
44        System.out.println(color);
45    }
46
47    public String getName(){
48        return name;
49    }
50
51    public void setName(String catName){
52        name = catName;
53    }
54
55    public String getColor(){
56        return color;
57    }
58
59    public void setColor(String catColor){
60        color = catColor;
61    }
62
63    public void move(){
64        //Переопределяем метод move. 
65        //Теперь движения кошки будут выводится как:
66        //"The cat gracefully walks and jumps.".
67        System.out.println("The cat gracefully walks and jumps.");
68    }
69}
70
71class Polimorphism2 {
72    public static void main(String[] args) {
73        Cat cat = new Cat();
74        // Воспользуемся методом move.
75        cat.move();
76        // Если бы метод move не был переопределён,
77        // на консоль вывелось бы "The animal moves."
78        // Но для кошки корректнее — "The cat gracefully 
79        // walks and jumps."
80    }
81}

Вывод:

Каждое животное, наследующее класс Animal, может по-своему переопределить метод move(). Так, у птицы это может быть “летает”, у собаки — “бежит”, и так далее.

Переопределение методов — мощный механизм, позволяющий делать поведение объектов более точным и соответствующим их конкретному типу, оставаясь при этом в рамках единой абстракции.


Следующие уроки

Абстрактный класс

16
мин.

Similar Articles Icon
Divider

Интерфейсы в Java

13
мин.

Similar Articles Icon
Divider

Статические поля

10
мин.

Similar Articles Icon