Полиморфизм и динамическое связывание в Java

Источник: DZone Полиморфизм — одна из основных концепций объектно-ориентированного программирования. Будь вы новичок в программировании на Java или разработчик с большим опытом работы, вы должны знать, что такое полиморфизм и как он работает. Большинство разработчиков утверждают, что хорошо разбираются в этой теме, но когда дело доходит до других сложных функций, таких как статическая и динамическая привязка, многие из них теряют былую уверенность. Кофе-брейк #111. Полиморфизм и динамическое связывание в Java. Цикл for в Java + пример синтаксиса цикла forEach - 1

Что такое полиморфизм в Java?

Полиморфизм означает наличие множества форм. В программировании это означает способность сигнала или сообщения отображаться более чем в одной форме.

Пример из реальной жизни

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

Важность полиморфизма

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

Типы полиморфизма

В Java полиморфизм можно разделить на две категории:
  1. Полиморфизм времени компиляции (Compile-time, статическое связывание)
  2. Полиморфизм времени выполнения (Runtime, динамическое связывание)

Полиморфизм времени компиляции

Полиморфизм времени компиляции также известен как статическое связывание. Этот тип полиморфизма может быть достигнут путем перегрузки функций или перегрузки операторов. Но в Java это ограничено перегрузкой функций, поскольку Java не поддерживает перегрузку операторов. Перегрузка функций Когда есть по крайней мере две функции или метода с одинаковым именем функции, но либо число содержащихся в них параметров разное, либо хотя бы один тип данных соответствующего параметра отличается (или оба), тогда это называется функцией или методом перегрузки, и эти функции известны как перегруженные функции. Пример 1 До сих пор мы изучали, что такое перегрузка функций. Теперь попробуем продемонстрировать программную перегрузку функций.

class Main {
 
    // Method 1
    // Method with 2 integer parameters
    static int Addition(int a, int b)
    {
 
        // Returns sum of integer numbers
        return a + b;
    }
    // Method 2
    // having the same name but with 2 double parameters
    static double Addition(double a, double b)
    {
        // Returns sum of double numbers
        return a + b;
    }
    public static void main(String args[]) {
        
        // Calling method by passing
        // input as in arguments
        System.out.println(Addition(12, 14));
        System.out.println(Addition(15.2, 16.1));
 
    }
}
Запустить указанную выше программу вы можете здесь. Объяснение программы:
  • Вышеприведенная программа состоит из двух статических функций с одинаковыми именами: Addition.

  • Здесь обе функции содержат одинаковое количество параметров, но соответствующие им параметры различны.

  • Method 1 принимает два целочисленных параметра, тогда как Method 2 принимает два параметра типа double.

  • Из основной функции мы сначала вызываем функцию Addition(12, 14). Передаваемые параметры являются целыми числами (12 и 14), поэтому Method 1 будут вызываться здесь.

  • Затем мы вызвали функцию Addition(15.2, 16.1). Поскольку переданные параметры имеют двойной тип данных (15.2 и 16.1), в этот раз будет вызван Method 2.

  • Именно так достигается перегрузка функций в Java на основе различных типов данных параметров.

Пример 2 Рассмотрим программу, приведенную ниже:

class Main {
 
    // Method 1
    // Method with 2 integer parameters
    static int Addition(int a, int b)
    {
 
        // Returns sum of integer numbers
        return a + b;
    }
 
    // Method 2
    // having the same name but with 3 integer parameters
    static double Addition(double a, double b)
    {
 
        // Returns sum of integer numbers
        return a + b;
    }
    public static void main(String args[]) {
        
        // Calling method by passing
        // input as in arguments
        System.out.println(Addition(12, 14));
        System.out.println(Addition(15.2, 16.1));
 
    }
}
Запустить указанную выше программу можно здесь. Объяснение программы:
  • Приведенная выше программа состоит из двух статических функций с одинаковыми именами: Addition.

  • Здесь обе функции содержат разное количество параметров, но тип данных первых двух соответствующих параметров одинаков (целочисленный).

  • Method 1 принимает два целочисленных параметра, а Method 2 принимает три параметра целочисленного типа данных.

  • Из основной функции мы сначала вызываем функцию Addition(2, 3). Поскольку переданные параметры являются целыми числами (2 и 3), они будут вызывать здесь Method 1.

  • Затем мы вызвали функцию Addition(4, 5, 6). Передаваемые параметры являются двойными типами данных (4, 5, 6), поэтому в этот раз они будут вызывать Method 2.

  • Так достигается перегрузка функций в Java на основе разного количества параметров.

Пример 3

class Main {
 
    // Method 1
    // Method with 2 integer parameters
    static int Addition(int a, int b)
    {
        // Return the sum
        return a + b;
    }
    // Method 2
    // having the same name but with 3 parameters
    // 1st parameter is of type double and other parameters
    // are of type integer
    static double Addition(double a, int b,  int c)
    {
        // Return the sum
        return a + b + c;
    }
    public static void main(String args[]) {
        
        // Calling method by passing
        // input as in arguments
        System.out.println(Addition(2, 4));
        System.out.println(Addition(4.2, 6, 10));
 
    }
}
Вы можете запустить указанную выше программу здесь. Объяснение программы:
  • Вышеприведенная программа состоит из двух статических функций с одинаковыми именами: Addition.

  • Обе функции содержат разное количество параметров и тип данных первого соответствующего элемента также отличается.

  • Method 1 принимает два целочисленных параметра, тогда как Method 2 принимает три параметра — первый имеет тип double, а два других — целочисленные типы данных.

  • Из основной функции мы сначала вызываем функцию Addition(2, 4). Поскольку переданные параметры являются целыми числами (2 и 4), они будут вызывать здесь Method 1.

  • Затем мы вызвали функцию Addition(4.2, 6, 10). Первый переданный параметр имеет целочисленный тип, а остальные параметры имеют тип данных double (4.2, 6, 10), поэтому в этот раз будет вызван Method 2.

  • Вот как в Java достигается перегрузка функций на основе разного количества параметров, а также разных типов данных соответствующих параметров.

Примечание. Функция не может быть перегружена только на основе возвращаемого типа функций.

Полиморфизм времени выполнения

Этот вариант также известен как динамическое связывание. В этом процессе вызов функции, созданной для другой функции, разрешается только во время выполнения. Мы можем добиться динамического связывания в Java с помощью переопределения методов.

Переопределение метода

Переопределение метода в Java происходит, когда метод в базовом классе имеет определение в производном классе. Метод или функция базового класса называется переопределенным методом.

// Class 1
class Parent {
 
    // Print method
    void Print()
    {
 
        // Print statement
        System.out.println("Inside Parent Class");
    }
}
 
// Class 2
class Child1 extends Parent {
 
    // Print method
    void Print() { System.out.println("Inside Child1 Class"); }
}
 
// Class 3
class Child2 extends Parent {
 
    // Print method
    void Print()
    {
        // Print statement
        System.out.println("Inside Child2 Class");
    }
}
 
class Main {
 
    public static void main(String args[]) {
        
        // Creating an object of class Parent
        Parent parent = new Parent();
        parent.Print();
 
        // Calling print methods
        parent = new Child1();
        parent.Print();
 
        parent = new Child2();
        parent.Print();
    }
}
Вы можете запустить указанную выше программу здесь. Объяснение программы:
  • Вышеупомянутая программа состоит из трех классов: Parent (class 1), Child1 (class 2) и Child2 (class 3). Class 2 и class 3 наследуют class 1.

  • У Parent есть метод под названием Print(). Внутри этой функции мы печатаем "Inside Parent Class". Child1 и Child2 также имеют функции Print(), которые в основном переопределяют Print() функцию класса Parent и выводят "Inside Child1 Class" и "Inside Child2 Class" соответственно на консоль.

  • Из основной функции мы сначала создаем объект родительского класса с именем parent. Затем с помощью этого объекта мы вызываем метод печати класса parent. Поэтому "Inside Parent Class" будет выведен на консоли.

  • После этого мы вызываем конструктор класса Child1 по умолчанию и вызываем функцию Print(). Обратите внимание, что теперь будет вызываться метод Print(), определенный в классе Child1, поскольку мы переопределили метод Print() класса parent. Следовательно, "Inside Child1 Class" будет напечатано на консоли.

  • Наконец, мы вызвали конструктор класса Child2 по умолчанию и вызываем функцию Print(). Здесь будет вызываться метод Print(), определенный в классе Child2, поскольку мы переопределили метод Print() класса parent. Следовательно, “Inside Child2 Class” будет напечатано на консоли.

  • Именно так достигается переопределение методов в Java.

Итоги

В этой статье мы узнали, что такое полиморфизм в Java. Затем мы углубились в тему и обсудили два типа полиморфизма в Java: полиморфизм времени компиляции и полиморфизм времени выполнения. С помощью программ мы продемонстрировали, как можно добиться статического и динамического связывания в Java.

Цикл for в Java + пример синтаксиса цикла forEach

Источник: FreeCodeCamp Цикл (Loop) в программировании — это последовательность инструкций, которые выполняются непрерывно до тех пор, пока не будет выполнено определенное условие. В этой статье мы узнаем о циклах for и forEach в Java. Кофе-брейк #111. Полиморфизм и динамическое связывание в Java. Цикл for в Java + пример синтаксиса цикла forEach - 2

Синтаксис цикла for в Java

Перед вами синтаксис создания цикла for:

for (initialization; condition; increment/decrement) {
   // code to be executed
}
Давайте разберем некоторые ключевые слова, приведенные в коде:
  • for указывает, что мы собираемся создать цикл. За ним следуют круглые скобки, в которых содержится все необходимое для работы нашего цикла.

  • initialization определяет начальную переменную как начальную точку цикла, обычно целое число.

  • condition указывает, сколько раз цикл должен выполняться.

  • increment/decrement увеличивает/уменьшает значение начальной переменной каждый раз, когда запускается цикл. По мере увеличения/уменьшения значение переменной стремится к заданному условию.

  • Обратите внимание, что каждое ключевое слово отделяется точкой с запятой (;).

Вот несколько примеров:

for(int x = 1; x <=5; x++) {
  System.out.println(x);
}

/*
1
2
3
4
5
*/
В приведенном выше примере начальная переменная — это x со значением 1. Цикл будет продолжать работать до тех пор, пока значение x меньше или равно 5 — это условие. x++ увеличивает значение x после каждого запуска. Мы продолжили печатать значение x, которое останавливается после 5, потому что условие было выполнено. Увеличение до 6 невозможно, потому что оно больше и не равно 5. В следующем примере мы будем использовать цикл for для вывода всех значений массива.

int[] randomNumbers = {2, 5, 4, 7};
for (int i = 0; i < randomNumbers.length; i++) {
  System.out.println(randomNumbers[i]);
}

// 2
// 5
// 4
// 7
Это почти то же самое, что и в последнем примере. Здесь мы использовали длину массива в качестве условия и начальное значение переменной как нулевое, потому что порядковый номер первого элемента массива равен нулю.

Синтаксис цикла forEach в Java

Цикл forEach используется специально для перебора элементов массива. Вот как выглядит его синтаксис:

for (dataType variableName : arrayName) {
  // code to be executed
}
Вы заметите, что синтаксис здесь короче, чем у цикла for. И цикл forEach также начинается с ключевого слова for. Вместо инициализации переменной значением мы сначала указываем тип данных (он должен соответствовать типу данных массива). Далее следует имя нашей переменной и имя массива, разделенные двоеточием. Вот пример, который поможет вам лучше понять синтаксис:

int[] randomNumbers = {2, 5, 4, 7};
for (int x : randomNumbers) {
  System.out.println(x + 1);
}

/*
3
6
5
8
*/
В этом примере мы перебрали каждый элемент и увеличили их начальное значение на 1. По умолчанию цикл останавливается, как только он перебирает все элементы массива. Это означает, что нам не требуется передавать какое-либо значение нашей переменной или указывать какое-либо условие для завершения цикла.

Заключение

В этой статье мы узнали, что такое циклы, а также синтаксис для создания циклов for и forEach в Java. Мы также увидели несколько примеров, которые помогли нам понять, когда и как их использовать. Удачного кодирования!