Что такое ложный полиморфизм (псевдополиморфизм) в ООП?

Ответ

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

Пример проблемы:

class Parent {
    void process(String data) {
        System.out.println("Parent processing: " + data);
    }
}

class Child extends Parent {
    // Это ПЕРЕГРУЗКА, а не переопределение!
    void process(Integer data) {
        System.out.println("Child processing: " + data);
    }
}

public class Main {
    public static void main(String[] args) {
        Parent obj = new Child();
        obj.process("test"); // Вызовет Parent.process(String)
        // obj.process(123); // Ошибка компиляции! Parent не имеет метода process(Integer)
    }
}

Почему это происходит и как избежать:

  • Причина: Сигнатуры методов (имя + типы параметров) не совпадают.
  • Решение: Всегда используйте аннотацию @Override. Компилятор выдаст ошибку, если метод не переопределяет существующий.
    class CorrectChild extends Parent {
    @Override // Компилятор проверит, что метод существует в родителе
    void process(String data) {
        System.out.println("CorrectChild processing: " + data);
    }
    }

Ответ 18+ 🔞

А, слушай, вот это классика, блядь! Прямо как в том анекдоте про Герасима и Муму — думаешь, одно, а на деле выходит нихуя не то.

Вот представь себе, сидишь ты такой, довольный, пишешь свой класс-наследник. Думаешь: «О, я сейчас тут всё переопределю, полиморфизмом, блядь, всех уделаю!». А в итоге получается ложный полиморфизм, или, как его умные дяди называют, псевдополиморфизм. Суть в чём, блядь? Ты в дочернем классе пишешь метод с таким же именем, но с другими параметрами. И думаешь: «Ну всё, я красава, я переопределил!». А компилятор смотрит на это и тихо охуевает. Потому что это не переопределение, а самая натуральная перегрузка (overloading). И когда ты пытаешься вызвать этот метод через ссылку на родителя — пиздец, волнение ебать! — работает родительский метод, а не твой «переопределённый». Потому что полиморфизм тут нихуя не работает.

Смотри, вот тебе живой пример, прямо как в жизни:

class Parent {
    void process(String data) {
        System.out.println("Parent processing: " + data);
    }
}

class Child extends Parent {
    // Это ПЕРЕГРУЗКА, а не переопределение!
    void process(Integer data) {
        System.out.println("Child processing: " + data);
    }
}

public class Main {
    public static void main(String[] args) {
        Parent obj = new Child();
        obj.process("test"); // Вызовет Parent.process(String)
        // obj.process(123); // Ошибка компиляции! Parent не имеет метода process(Integer)
    }
}

Видишь эту подлянку? Ты создал Child, положил его в переменную типа Parent — вроде всё по канону. Зовёшь process("test") — и на тебе, сука, выполняется метод бати! А твой новый метод с Integer вообще в игноре, до него даже дотянуться нельзя через эту ссылку. Вообще пиздец, обман на доверии, ебать ноль.

А в чём корень зла, спросишь? Да всё просто, как три копейки: сигнатуры-то разные! Имя одно — process, а принимают они разное: String и Integer. Для компилятора это два абсолютно разных метода. И когда он ищет, что вызвать через Parent obj, он смотрит только на методы, объявленные в Parent. А там только process(String). Вот он его и вызывает. Твой process(Integer) — это просто другой метод в классе Child, он в этой полиморфной игре вообще не участвует. Чистая иллюзия, пиздопроебибна!

Как не попасть в эту ебучую ловушку? Есть же простой, гениальный способ, ядрёна вошь! Всегда, блядь, всегда ставь аннотацию @Override. Это как страховочный трос. Написал метод, сверху @Override — и компилятор сразу проверит: «А есть ли, сука, такой метод у родителя, который ты собрался переопределить?». Если нет — тут же вмандят тебе ошибку на этапе компиляции, и ты не будешь потом, как Герасим, с мукой в душе метаться и думать: «Что же я, мудак, сделал?».

class CorrectChild extends Parent {
    @Override // Компилятор проверит, что метод существует в родителе
    void process(String data) {
        System.out.println("CorrectChild processing: " + data);
    }
}

Вот теперь — красота! Сигнатуры совпали, аннотация на месте. Теперь-то уж точно, когда вызовешь через Parent obj = new CorrectChild(), сработает метод дитёнка. Полиморфизм во всей своей красе, а не эта хуйня с горы. Запомни, чувак: @Override — твой лучший друг в борьбе с ложными надеждами и псевдополиморфизмом.