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

Что такое сокрытие метода?

1.2 Junior🔥 121 комментариев
#ООП

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

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

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

Сокрытие метода (Method Hiding) в Java

Сокрытие метода — это явление, которое происходит когда дочерний класс объявляет статический метод с той же сигнатурой, что и статический метод в родительском классе. Это ОТЛИЧАЕТСЯ от переопределения (overriding), которое работает с нестатическими методами.

Ключевое отличие: Method Hiding vs Method Overriding

Method Overriding (переопределение) — для обычных (нестатических) методов:

public class Parent {
    // Обычный метод
    public void display() {
        System.out.println("Parent display");
    }
}

public class Child extends Parent {
    @Override
    public void display() {  // Переопределение
        System.out.println("Child display");
    }
}

// Использование
Parent p = new Child();
p.display();  // Выведет: Child display (полиморфизм работает)

Method Hiding (сокрытие) — для статических методов:

public class Parent {
    // Статический метод
    public static void display() {
        System.out.println("Parent static display");
    }
}

public class Child extends Parent {
    // Это сокрытие, не переопределение
    public static void display() {
        System.out.println("Child static display");
    }
}

// Использование
Parent p = new Child();
p.display();          // Выведет: Parent static display (НЕ полиморфизм!)
Child c = new Child();
c.display();          // Выведет: Child static display
Parent.display();     // Выведет: Parent static display
Child.display();      // Выведет: Child static display

Почему это происходит?

Статические методы привязаны к КЛАССУ, а не к объекту. Статические методы вызываются на этапе компиляции, основываясь на типе переменной, а не на типе объекта.

public class Example {
    public static void main(String[] args) {
        // Тип переменной = Parent
        // Тип объекта = Child
        // Но для static методов имеет значение ТИП ПЕРЕМЕННОЙ!
        Parent reference = new Child();
        reference.staticMethod();  // Вызовет Parent.staticMethod()
        
        // Для обычных методов имеет значение ТИП ОБЪЕКТА
        reference.instanceMethod();  // Вызовет Child.instanceMethod()
    }
}

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

public class Animal {
    public static void makeSound() {
        System.out.println("Some generic sound");
    }
    
    public void eat() {
        System.out.println("Animal is eating");
    }
}

public class Dog extends Animal {
    // Сокрытие статического метода
    public static void makeSound() {
        System.out.println("Woof! Woof!");
    }
    
    // Переопределение нестатического метода
    @Override
    public void eat() {
        System.out.println("Dog is eating dog food");
    }
}

public class Cat extends Animal {
    // Сокрытие статического метода
    public static void makeSound() {
        System.out.println("Meow! Meow!");
    }
    
    @Override
    public void eat() {
        System.out.println("Cat is eating cat food");
    }
}

public class Demo {
    public static void main(String[] args) {
        // Статические методы - сокрытие
        Animal.makeSound();           // Some generic sound
        Dog.makeSound();              // Woof! Woof!
        Cat.makeSound();              // Meow! Meow!
        
        // Через ссылку Animal - вызывает Animal.makeSound()
        Animal animalRef = new Dog();
        animalRef.makeSound();        // Some generic sound (сокрытие!)
        
        // Нестатические методы - переопределение (полиморфизм)
        Animal dog = new Dog();
        Animal cat = new Cat();
        
        dog.eat();  // Dog is eating dog food (переопределение)
        cat.eat();  // Cat is eating cat food (переопределение)
    }
}

Вывод:

Статические методы (СОКРЫТИЕ):
- Animal.makeSound()  →  "Some generic sound"
- Dog.makeSound()     →  "Woof! Woof!"
- Animal ref→Dog.makeSound() → "Some generic sound" (вызывается по типу переменной!)

Нестатические методы (ПЕРЕОПРЕДЕЛЕНИЕ):
- dog.eat()  →  "Dog is eating dog food" (вызывается по типу объекта!)
- cat.eat()  →  "Cat is eating cat food"

Проблемы и лучшие практики

Проблема: потенциальная путаница

public class Parent {
    public static void show() {
        System.out.println("Parent.show()");
    }
}

public class Child extends Parent {
    // Опасно: коллеги могут ошибочно подумать, что это переопределение
    public static void show() {
        System.out.println("Child.show()");
    }
}

// Результат может быть неожиданным
Parent p = new Child();
p.show();  // Вызовет Parent.show(), хотя многие ожидают Child.show()

Решение: использовать аннотацию @Override с осторожностью

public class Child extends Parent {
    // @Override сработает, но это НЕ переопределение!
    // (компилятор выдаст предупреждение в некоторых IDE)
    public static void show() {
        System.out.println("Child.show()");
    }
}

Когда используется сокрытие методов?

  1. Утилиты классы — часто содержат только статические методы:
public class StringUtils {
    public static String uppercase(String s) {
        return s.toUpperCase();
    }
}

public class SpecialStringUtils extends StringUtils {
    // Сокрытие для специального поведения
    public static String uppercase(String s) {
        return "*** " + s.toUpperCase() + " ***";
    }
}
  1. Фабричные методы в иерархиях классов:
public class DataSource {
    public static DataSource create() {
        return new DataSource();
    }
}

public class AdvancedDataSource extends DataSource {
    public static AdvancedDataSource create() {
        return new AdvancedDataSource();
    }
}

Рекомендации

  • Избегайте сокрытия методов если это не абсолютно необходимо
  • Используйте полиморфизм (нестатические методы) для реализации различного поведения в подклассах
  • Избегайте вызова статических методов через объекты — вызывайте через имя класса: Dog.makeSound(), а не dog.makeSound()
  • Если необходимо сокрытие — документируйте это явно в коде

Сокрытие методов — это хорошо известное явление в Java, но обычно его следует избегать в пользу более предсказуемого полиморфизма для нестатических методов.