← Назад к вопросам

В чем разница между истинным и ложным полиморфизмом?

1.7 Middle🔥 111 комментариев
#ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Истинный и ложный полиморфизм в Java

Полиморфизм — фундаментальный принцип ООП. В Java различают истинный полиморфизм (динамическую диспетчеризацию) и ложный (статическую и другие механизмы).

Истинный полиморфизм (Полиморфизм подтипов)

Это полиморфизм наследования, когда решение о том, какой метод вызывать, принимается во время выполнения (runtime) на основе фактического типа объекта.

interface Animal {
    void sound();
}

class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println("Гав!");
    }
}

class Cat implements Animal {
    @Override
    public void sound() {
        System.out.println("Мяу!");
    }
}

public class TruePolymorphism {
    public static void main(String[] args) {
        // Ссылка типа Animal, но объект типа Dog
        Animal animal1 = new Dog();
        animal1.sound(); // Гав! - выбор метода во время RUNTIME
        
        // Ссылка типа Animal, но объект типа Cat
        Animal animal2 = new Cat();
        animal2.sound(); // Мяу! - выбор метода во время RUNTIME
        
        // Один и тот же код работает с разными типами
        Animal[] animals = {new Dog(), new Cat(), new Dog()};
        for (Animal a : animals) {
            a.sound(); // каждый вызовет свою реализацию
        }
    }
}

Характеристики истинного полиморфизма:

  • Динамическая диспетчеризация: выбор метода во время выполнения
  • Ковариантность типов: ссылка родителя может указывать на объект потомка
  • Переопределение (override): потомок переопределяет метод родителя
  • Virtual метод: в Java ВСЕ методы экземпляра — virtual по умолчанию
  • Гибкость: один код работает с разными типами без изменений

Ложный полиморфизм

1. Полиморфизм параметризации (Generics)

public class Container<T> {
    private T value;
    
    public void set(T value) {
        this.value = value;
    }
    
    public T get() {
        return value;
    }
}

public class GenericPolymorphism {
    public static void main(String[] args) {
        // Один класс работает с разными типами
        Container<String> stringContainer = new Container<>();
        stringContainer.set("Hello");
        
        Container<Integer> intContainer = new Container<>();
        intContainer.set(42);
        
        // Это НЕ истинный полиморфизм, а параметризация
        // В runtime тип T стирается (type erasure)
    }
}

2. Полиморфизм методов (Перегрузка/Overloading)

public class OverloadingPolymorphism {
    // Все эти методы имеют одно имя, но разные сигнатуры
    public void print(String s) {
        System.out.println("Строка: " + s);
    }
    
    public void print(int i) {
        System.out.println("Число: " + i);
    }
    
    public void print(double d) {
        System.out.println("Дробь: " + d);
    }
    
    public static void main(String[] args) {
        OverloadingPolymorphism obj = new OverloadingPolymorphism();
        obj.print("Hello");   // Выбор метода во время КОМПИЛЯЦИИ
        obj.print(42);        // Статическая диспетчеризация
        obj.print(3.14);
    }
}

3. Ad-hoc полиморфизм (Перегрузка операторов)

public class AdHocPolymorphism {
    public static void main(String[] args) {
        // Оператор + работает с разными типами
        String result1 = "Hello" + " World";  // конкатенация
        int result2 = 10 + 20;                  // сумма
        double result3 = 5.5 + 2.5;             // сумма дробей
        
        // Это ad-hoc полиморфизм, решение во время компиляции
    }
}

Сравнение: Static vs Dynamic Dispatch

class Animal {
    public void sound() {
        System.out.println("Издаёт звук");
    }
    
    public static void staticMethod() {
        System.out.println("Статический метод");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Гав!");  // ДИНАМИЧЕСКАЯ диспетчеризация
    }
    
    public static void staticMethod() {
        System.out.println("Статический метод Dog");
        // Это НЕ переопределение! Это СКРЫТИЕ метода
    }
}

public class DispatchComparison {
    public static void main(String[] args) {
        Animal animal = new Dog();
        
        // ИСТИННЫЙ полиморфизм: вызовет Dog.sound()
        animal.sound();  // Гав!
        
        // ЛОЖНЫЙ полиморфизм: вызовет Animal.staticMethod()
        animal.staticMethod();  // Статический метод
        // Выбор метода based on compile-time type (Animal), не runtime type (Dog)
    }
}

Таблица: истинный vs ложный полиморфизм

ХарактеристикаИстинный (Override)Ложный
Выбор методаRuntimeCompile-time
МеханизмДинамическая диспетчеризацияСтатическая диспетчеризация
КонтролПо фактическому типу объектаПо типу ссылки
ПримерыOverride, Interface, InheritanceOverloading, Generics, Static methods
ПроизводительностьЧуть медленнееЧуть быстрее

Практический пример: банковская система

abstract class Account {
    protected double balance;
    
    public abstract double calculateInterest();
    
    public void printInfo() {
        System.out.println("Баланс: " + balance);
        System.out.println("Процент: " + calculateInterest());
    }
}

class SavingsAccount extends Account {
    @Override
    public double calculateInterest() {
        return balance * 0.05;  // 5% годовых
    }
}

class CheckingAccount extends Account {
    @Override
    public double calculateInterest() {
        return balance * 0.01;  // 1% годовых
    }
}

public class BankSystem {
    public static void main(String[] args) {
        // ИСТИННЫЙ полиморфизм
        Account[] accounts = {
            new SavingsAccount(),
            new CheckingAccount(),
            new SavingsAccount()
        };
        
        // Один код работает с разными типами счётов
        for (Account acc : accounts) {
            acc.printInfo();  // вызовет правильный calculateInterest()
        }
    }
}

Почему истинный полиморфизм важен

  1. Расширяемость: добавьте новый тип, старый код работает
  2. SOLID принципы: Liskov Substitution Principle
  3. Слабая связанность: код не знает конкретные типы
  4. Тестируемость: легко подменять реальные объекты мок-объектами
// Расширение без изменения старого кода
class StudentAccount extends Account {
    @Override
    public double calculateInterest() {
        return balance * 0.02;  // 2% для студентов
    }
}

// Старый код "автоматически" работает с новым типом
Account studentAcc = new StudentAccount();
studentAcc.printInfo();  // работает! НЕ нужно менять BankSystem

Истинный полиморфизм — это сердце ООП. Он делает код гибким, расширяемым и поддерживаемым. Ложные формы полиморфизма полезны, но служат другим целям и не обеспечивают такой же уровень абстракции.