Статическое и динамическое связывание в Java

Статическое и динамическое связывание в Java

1. Вступление

Polymorphism позволяет объекту принимать несколько форм - когда метод демонстрирует полиморфизм, компилятор должен сопоставить имя метода с окончательной реализацией.

Если он отображается во время компиляции, это статическая или ранняя привязка.

Если проблема решена во время выполнения, она называется динамической или поздней привязкой.

2. Понимание через код

Когда подкласс расширяет суперкласс, он может повторно реализовать методы, определенные в нем. Это называется переопределением метода.

Например, давайте создадим суперклассAnimal:

public class Animal {

    static Logger logger = LoggerFactory.getLogger(Animal.class);

    public void makeNoise() {
        logger.info("generic animal noise");
    }

    public void makeNoise(Integer repetitions) {
        while(repetitions != 0) {
            logger.info("generic animal noise countdown " + repetitions);
            repetitions -= 1;
        }
    }
}

И подклассDog:

public class Dog extends Animal {

    static Logger logger = LoggerFactory.getLogger(Dog.class);

    @Override
    public void makeNoise() {
        logger.info("woof woof!");
    }

}

При перегрузке метода, такого какmakeNoise() классаAnimal, компилятор разрешит метод и его код во время компиляции. This is an example of static binding.

Однако, если мы присвоим объект типаDog ссылке типаAnimal, компилятор разрешит отображение кода функции во время выполнения. Это динамическое связывание.

Чтобы понять, как это работает, давайте напишем небольшой фрагмент кода для вызова классов и их методов:

Animal animal = new Animal();

// calling methods of animal object
animal.makeNoise();
animal.makeNoise(3);

// assigning a dog object to reference of type Animal
Animal dogAnimal = new Dog();

dogAnimal.makeNoise();

The output of the above code will be:
com.example.binding.Animal - generic animal noise
com.example.binding.Animal - generic animal noise countdown 3
com.example.binding.Animal - generic animal noise countdown 2
com.example.binding.Animal - generic animal noise countdown 1
com.example.binding.Dog - woof woof!

А теперь давайте создадим класс:

class AnimalActivity {

    public static void eat(Animal animal) {
        System.out.println("Animal is eating");
    }

    public static void eat(Dog dog) {
        System.out.println("Dog is eating");
    }
}

Давайте добавим эти строки в основной класс:

AnimalActivity.eat(dogAnimal);

Выход будет:

com.example.binding.AnimalActivity - Animal is eating

This example shows that a static function undergoes static binding.

Причина в том, что подклассы не могут переопределять статические методы. Если бы подкласс реализовал тот же метод, он бы скрыл метод суперкласса. Similarly, if a method is final or private, the JVM will do a static binding.с

Статический связанный метод не связан с конкретным объектом, а скорее вызывается вType (класс в Java). Выполнение такого метода незначительно быстрее.

Любой другой метод автоматически является виртуальным методом в Java по умолчанию. JVM разрешает такие методы во время выполнения, и это динамическое связывание.

Точная реализация зависит от JVM, но для этого потребуется подход, подобный C ++, где JVM ищет виртуальную таблицу, чтобы решить, какой объект будет вызываться методом.

3. Заключение

Связывание является неотъемлемой частью языка, реализующего полиморфизм, важно понимать последствия статического и динамического связывания, чтобы быть уверенным, что наши приложения ведут себя так, как мы хотим.

Однако с этим пониманием мы можем эффективно использовать наследование классов, а также перегрузку методов.

Как всегда доступен кодover on GitHub.