Что такое полиморфизм с точки зрения реализации в коде?

Ответ

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

Ключевые реализации в Java:

  • Через наследование и переопределение методов:

    // Общий интерфейс (можно использовать абстрактный класс или интерфейс)
    interface Shape {
        double getArea(); // Общая сигнатура
    }
    
    class Circle implements Shape {
        private double radius;
        Circle(double r) { this.radius = r; }
        @Override
        public double getArea() { // Конкретная реализация 1
            return Math.PI * radius * radius;
        }
    }
    
    class Square implements Shape {
        private double side;
        Square(double s) { this.side = s; }
        @Override
        public double getArea() { // Конкретная реализация 2
            return side * side;
        }
    }
    
    // Использование
    List<Shape> shapes = Arrays.asList(new Circle(5), new Square(4));
    for (Shape s : shapes) {
        // Вызывается getArea(), но для каждого объекта своя реализация
        System.out.println("Area: " + s.getArea());
    }
  • Через перегрузку методов в одном классе:

    class Logger {
        // Одно имя, разные параметры
        void log(String message) {
            System.out.println("[INFO] " + message);
        }
        void log(String message, int severity) {
            System.out.println("[" + severity + "] " + message);
        }
        void log(Exception e) {
            System.err.println("[ERROR] " + e.getMessage());
        }
    }

Практическая польза: Код, использующий полиморфизм, становится:

  • Более читаемым: операции выражаются в общих терминах (shape.getArea()).
  • Слабо связанным: клиентский код зависит от абстракции (Shape), а не от конкретных классов.
  • Удобным для тестирования: легко подменять реальные объекты mock-объектами, реализующими тот же интерфейс.

Ответ 18+ 🔞

Давай разберём эту тему, но без занудства, как есть. Полиморфизм, блядь — это когда ты одной и той же командой можешь заставить разные объекты делать своё, сука, дело. Представь, крикнул ты "Пой!" — один затянет оперу, другой рэпчик, третий вообще матерный частушку, а четвёртый, пидарас шерстяной, просто мычит. А команда-то одна — "пой". Вот это и есть полиморфизм, ёпта.

Как это в коде выглядит, на примере:

Допустим, у нас есть понятие "Фигура". Все фигуры должны уметь считать площадь, но каждая — по-своему, блядь. Круг — через пи-ар-квадрат, квадрат — сторону на сторону, треугольник — там своя хуйня.

// Вот общий контракт, типа "все, кто хочет быть фигурой, должны уметь это делать"
interface Shape {
    double getArea(); // Сигнатура одна — "дай площадь"
}

// А теперь конкретные ребята, которые этот контракт выполняют, но как хотят
class Circle implements Shape {
    private double radius;
    Circle(double r) { this.radius = r; }
    @Override
    public double getArea() { // Реализация первая, для кругляша
        return Math.PI * radius * radius;
    }
}

class Square implements Shape {
    private double side;
    Square(double s) { this.side = s; }
    @Override
    public double getArea() { // Реализация вторая, для квадратного чурбана
        return side * side;
    }
}

// А теперь магия, блядь! Собираем их в кучу
List<Shape> shapes = Arrays.asList(new Circle(5), new Square(4));
for (Shape s : shapes) {
    // Вот тут-то и полиморфизм! Для каждого объекта вызывается СВОЙ getArea()
    System.out.println("Area: " + s.getArea());
}

Видишь? В цикле мы нихуя не знаем, круг там или квадрат. Мы просто орём "дай площадь!". А объект сам уже разбирается, как ему это сделать. Это и есть красота, в рот меня чих-пых!

Есть ещё перегрузка — это когда в одном классе несколько методов с одним именем, но разными параметрами. Типа:

class Logger {
    void log(String message) {
        System.out.println("[INFO] " + message);
    }
    void log(String message, int severity) { // Тот же log, но с доп. инфой
        System.out.println("[" + severity + "] " + message);
    }
    void log(Exception e) { // И тот же log, но для ошибки
        System.err.println("[ERROR] " + e.getMessage());
    }
}

Тут компилятор сам, хитрая жопа, смотрит, какие аргументы ты передал, и решает, какой именно метод log вызвать. Тоже полиморфизм, но статический, на этапе компиляции.

А нахуя это всё нужно, спросишь? Да затем, что код становится, как хороший конструктор:

  • Читаемым: не надо городить if (это круг) {считай так} else if (это квадрат) {считай эдак}. Просто getArea() и похуй.
  • Расширяемым: захотел добавить треугольник — написал класс Triangle, реализовал getArea() по-своему, и весь старый код, который работает с Shape, будет с ним работать. Ничего переписывать не надо, волнение ебать!
  • Удобным для тестирования: легко подсунуть заглушку (mock), которая тоже реализует Shape, и проверить, как твой код с ней взаимодействует.

Вот и вся философия. Не усложняй, просто помни: один интерфейс — много реализаций. Как в жизни: команда "работай!" — один копает, другой пишет, третий начальник, сука, кофе пьёт. А команда одна.