Polymorphism
The dictionary definition of polymorphism refers to a principle in biology in which an organism or species can have many different forms or stages. This principle can also be applied to object-oriented programming and languages like the Java language. Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class.
Polymorphism can be demonstrated with a minor modification to the Bicycle class. For example, a printDescription method could be added to the class that displays all the data currently stored in an instance.
To demonstrate polymorphic features in the Java language, extend the Bicycle class with a MountainBike and a RoadBike class. For MountainBike , add a field for suspension , which is a String value that indicates if the bike has a front shock absorber, Front . Or, the bike has a front and back shock absorber, Dual .
Here is the updated class:
Note the overridden printDescription method. In addition to the information provided before, additional data about the suspension is included to the output.
Next, create the RoadBike class. Because road or racing bikes have skinny tires, add an attribute to track the tire width. Here is the RoadBike class:
Note that once again, the printDescription method has been overridden. This time, information about the tire width is displayed.
To summarize, there are three classes: Bicycle , MountainBike , and RoadBike . The two subclasses override the printDescription method and print unique information.
Here is a test program that creates three Bicycle variables. Each variable is assigned to one of the three bicycle classes. Each variable is then printed.
The following is the output from the test program:
The Java virtual machine (JVM) calls the appropriate method for the object that is referred to in each variable. It does not call the method that is defined by the variable's type. This behavior is referred to as virtual method invocation and demonstrates an aspect of the important polymorphism features in the Java language.
Что такое полиморфизм в Java
Привет! Это статья об одном из принципов ООП — полиморфизм.
Что такое полиморфизм
Определение полиморфизма звучит устрашающе
Полиморфизм — это возможность применения одноименных методов с одинаковыми или различными наборами параметров в одном классе или в группе классов, связанных отношением наследования.
Слово «полиморфизм» может показаться сложным — но это не так. Нужно просто разбить данное определение на части и показать на примерах, что имеется в виду. Поверьте, уже в конце статьи данное определение полиморфизма покажется Вам понятным
Полиморфизм, если перевести, — это значит «много форм». Например, актер в театре может примерять на себя много ролей — или принимать «много форм».
Так же и наш код — благодаря полиморфизму он становится более гибким, чем в языках программирования, которые не используют принципы ООП.
Так о каких формах идет речь? Давайте сначала приведем примеры и покажем, как на практике проявляется полиморфизм, а потом снова вернемся к его определению.
Как проявляется полиморфизм
Дело в том, что если бы в Java не было принципа полиморфизма, компилятор бы интерпретировал это как ошибку:
Как видите, методы на картинке отличаются значениями, которые они принимают:
- первый принимает int
- а второй принимает String
Однако, поскольку в Java используется принцип полиморфизма, компилятор не будет воспринимать это как ошибку, потому что такие методы будут считаться разными:
Называть методы одинаково — это очень удобно. Например, если у нас есть метод, который ищет корень квадратный из числа, гораздо легче запомнить одно название (например, sqrt()), чем по одному отдельному названию на этот же метод, написанный для каждого типа:
Как видите, мы не должны придумывать отдельное название для каждого метода — а главное их запоминать! Очень удобно.
Теперь Вы можете понять, почему часто этот принцип описывают фразой:
Один интерфейс — много методов
Это предполагает, что мы можем заполнить одно название (один интерфейс), по которому мы сможем обращаться к нескольким методам.
Перегрузка методов
То, что мы показывали выше — несколько методов с одним названием и разными параметрами — называется перегрузкой. Но это был пример перегрузки метода в одном классе. Но бывает еще один случай — переопределение методов родительского класса.
Переопределение методов родителя
Когда мы наследуем какой-либо класс, мы наследуем и все его методы. Но если нам хочется изменить какой-либо из методов, который мы наследуем, мы можем всего-навсего переопределить его. Мы не обязаны, например, создавать отдельный метод с похожим названием для наших нужд, а унаследованный метод будет «мертвым грузом» лежать в нашем классе.
Именно то, что мы можем создать в классе-наследнике класс с таким же названием, как и класс, который мы унаследовали от родителя, и называется переопределением.
Пример
Представим, что у нас есть такая структура:
Вверху иерархии классов стоит класс Animal. Его наследуют три класса — Cat, Dog и Cow.
У класса «Animal» есть метод «голос» (voice). Этот метод выводит на экран сообщение «Голос». Естественно, ни собака, ни кошка не говорят «Голос» Они гавкают и мяукают. Соответственно, Вам нужно задать другой метод для классов Cat, Dog и Cow — чтобы кошка мяукала, собака гавкала, а корова говорила «Муу».
Поэтому, в классах-наследниках мы переопределяем метод voice(), чтобы мы в консоли получали «Мяу», «Гав» и «Муу».
- Обратите внимание: перед методом, который мы переопределяем, пишем «@Override«. Это дает понять компилятору, что мы хотим переопределить метод.
Так что же такое полиморфизм
Тем не менее, полиморфизм — это принцип. Все реальные примеры, которые мы приведодили выше — это только способы реализации полиморфизма.
Давайте снова посмотрим на определение, которое мы давали в начале статьи:
Полиморфизм — возможность применения одноименных методов с одинаковыми или различными наборами параметров в одном классе или в группе классов, связанных отношением наследования.
Выглядит понятнее, правда? Мы показали, как можно:
- создавать «одноименные методы» в одном классе («перегрузка методов»)
- или изменить поведение методов родительского класса («переопределение методов»).
Все это — проявления «повышенной гибкости» объектно-ориентированных языков благодаря полиморфизму.
Надеемся, наша статья была Вам полезна. Записаться на наши курсы по Java можно у нас на сайте.
Master Polymorphism in Java With Examples
In the real world, you might have seen a chameleon changing its color as per its requirement. If someone asks, “How it does that?”, you can simply say, “Because, it is polymorphic”. Similarly, in the programming world, Java objects possess the same functionality where each object can take multiple forms. This property is known as Polymorphism in Java, where Poly means many and morph means change (or ‘form’). In this article, let’s discuss this key concept of Object Oriented Programming i.e. Polymorphism in Java.
Below are the topics to be covered in this article:
- What is Polymorphism?
- Polymorphism in Java with Example
- Types of Polymorphism in Java
- Static Polymorphism
- Dynamic Polymorphism
- Other Characteristics of Polymorphism in Java
What is Polymorphism?
Polymorphism is the ability of an entity to take several forms. In object-oriented programming, it refers to the ability of an object (or a reference to an object) to take different forms of objects. It allows a common data-gathering message to be sent to each class. Polymorphism encourages called as ‘extendibility’ which means an object or a class can have it’s uses extended.
In the above figure, you can see, Man is only one, but he takes multiple roles like — he is a dad to his child, he is an employee, a salesperson and many more. This is known as Polymorphism.
Now, let’s understand this by taking a real-life example and see how this concept fits into Object-oriented programming.
Polymorphism in Java with Example
Let’s understand this (the example) with the help of below problem statement.
Consider a cell phone where you save your Contacts. Suppose a person has two contact numbers. For the ease of accessibility, your cellphone provides you the functionality where you can save two numbers under the same name.
Similarly, in Java, an object is only one but it can take multiple forms depending on the context of the program. Suppose you want to write a function to save two contact numbers of the same person, you can create it like — void createContact(String name, int number1, int number2).
Now, it’s not necessary that everyone in your contact list will have two contact numbers. Few of them might be having only a single contact number. In such situations, instead of creating another method with a different name to save one number for a contact, what you can do is, create another method with the same name i.e. createContact(). But, instead of taking two contact numbers as parameters, take only one contact number as a parameter i.e. void createContact(String name, int number1).
As you can see in the above figure, createContact() method has two different definitions. Here, which definition is to be executed depends upon the number of parameters being passed. If one parameter is passed, then only a single contact number is saved under the contact. But, if two contact numbers are passed to this method at the same time, then both will be saved under the same contact. This is also known as Method Overloading.
Now let’s take another example and understand polymorphism in depth.
Suppose you went to a Shopping Centre (Allen Solly) near your home and bought a pair of jeans. A week later, while traveling to a nearby town, you spot another Shopping center. You walk into the shop and find a new variant of the same brand which you liked even more. But you decided to buy it from the shop near to your home. Once back home, you again went to the Shopping Center near your home to get those amazing pair of Jeans but couldn’t find it. Why? Because that was a specialty of the shop that was located in the neighboring town.
Now relating this concept to an object-oriented language like Java, suppose you have a class named XJeans which includes a method named jeans(). Using this method, you can get an Allen Solly jeans. For the Jeans in the neighboring town, there is another class YJeans. Both the classes XJeans and YJeans extends the parent class ABCShoppingCenter. The YJeans class includes a method named jeans(), using which you can get both the jeans variants.
So, instead of creating different methods for every new variant, we can have a single method jeans(), which can be defined as per the different child classes. Thus, the method named jeans() has two definitions — one with only default jeans and other with both, the default jeans and the new variant. Now, which method gets invoked will depend on the type of object it belongs to. If you create ABCShoppingCenter class object, then there will be only one jeans available. But if you create YJeans class object, that extends ABCShoppingCenter class, then you can have both the variants. This is also known as Method Overriding. Thus, Polymorphism increases the simplicity and readability of the code by reducing the complexity. This makes Polymorphism in Java a very useful concept and it can be applied in real-world scenarios as well.
I hope you got an idea on the concept of Polymorphism. Now, let’s move further with this article and understand different types of Polymorphism in Java.
Types of Polymorphism in Java
Java supports two types of polymorphism and they are as follows:
- Static Polymorphism
- Dynamic Polymorphism
Static Polymorphism
A polymorphism that is resolved during compile time is known as static polymorphism. Method overloading is an example of compile-time polymorphism.
Example
Method Overloading is a feature that allows a class to have two or more method to have the same name, but with different parameter lists. In the below example, you have two definitions of the same method add(). So, which add() method would be called is determined by the parameter list at the compile time. That is the reason this is also known as compile time polymorphism.
This is how Static Polymorphism works. Now, let’s understand what is Dynamic Polymorphism in Java.
Dynamic Polymorphism
Dynamic polymorphism is a process in which a call to an overridden method is resolved at runtime, that’s why it is called runtime polymorphism. Method Overriding is one of the ways to achieve Dynamic Polymorphism. In any object-oriented programming language, Overriding is a feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its super-classes or parent classes.
Example
In the below example, you have two classes MacBook and iPad. MacBook is a parent class and iPad is a child class. The child class is overriding the method myMethod() of the parent class. Here, I have assigned child class object to the parent class reference to determine which method would be called at run-time. It is the type of object that determines which version of the method would be called (not the type of reference).
Output:
When you invoke the overriding method, then the object determines which method is to be executed. Thus, this decision is made at run time.
I have listed down few more overriding examples.
In the third example, the method of the child class is to be executed because the method that needs to be executed is determined by the type of object. Since the object belongs to the child class, the child class version of myMethod() is called.
Advantages of Dynamic Polymorphism
- Dynamic Polymorphism allows Java to support overriding of methods which is central for run-time polymorphism.
- It allows a class to specify methods that will be common to all of its derivatives while allowing subclasses to define the specific implementation of some or all of those methods.
- It also allows subclasses to add its specific methods subclasses to define the specific implementation of same.
This was all about different types. Now let’s see some important other characteristics of Polymorphism.
Other Characteristics of Polymorphism in Java
In addition to these two main types of polymorphism in Java, there are other characteristics in the Java programming language that exhibits polymorphism like:
- Coercion
- Operator Overloading
- Polymorphic Parameters
Let’s discuss some of these characteristics.
Coercion
Polymorphic coercion deals with implicit type conversion done by the compiler to prevent type errors. A typical example is seen in an integer and string concatenation.
Operator Overloading
An operator or method overloading refers to a polymorphic characteristic of same symbol or operator having different meanings (forms) depending on the context. For example, the plus symbol (+) is used for mathematical addition as well as String concatenation. In either case, only context (i.e. argument types) determines the interpretation of the symbol.
Output:
Polymorphic Parameters
Parametric polymorphism allows a name of a parameter or method in a class to be associated with different types. In the below example I have defined content as a String and later as an Integer:
Note: Declaration of polymorphic parameters can lead to a problem known as variable hiding.
Here, the local declaration of a parameter always overrides the global declaration of another parameter with the same name. To solve this problem, it is often advisable to use global references such as this keyword to point to global variables within a local context.
With this, we come to an end this article on article Polymorphism in Java. Do look out for other articles in the series which will help you understand various concepts of Java.
If you wish to check out more articles on the market’s most trending technologies like Artificial Intelligence, DevOps, Ethical Hacking, then you can refer to Edureka’s official site.
Do look out for other articles in this series which will explain the various other aspects of Java.
Java Challengers #3: Полиморфизм и наследование
Мы продолжаем перевод серии статей с задачками по Java. Прошлый пост про строки вызвал на удивление бурную дискуссию. Надеемся, что мимо этой статьи вы тоже не пройдете мимо. И да — мы приглашаем теперь на юбилейный десятый поток нашего курса «Разработчик Java».
Согласно легендарному Венкату Субраманиам (Venkat Subramaniam) полиморфизм является самым важным понятием в объектно — ориентированном программировании. Полиморфизм — или способность объекта выполнять специализированные действия на основе его типа — это то, что делает Java — код гибким. Шаблоны проектирования, такие как Команда (Command), Наблюдатель (Observer), Декоратор (Decorator), Стратегия (Strategy), и многие другие, созданные бандой четырех (Gang Of Four), все используют ту или иную форму полиморфизма. Освоение этой концепции значительно улучшит вашу способность продумывать программные решения.
Вы можете взять исходный код для этой статьи и поэксперементировать здесь: https://github.com/rafadelnero/javaworld-challengers
Интерфейсы и наследование в полиморфизме
В этой статье мы сфокусируемся на связи между полиморфизмом и наследованием. Главное иметь в виду, что полиморфизм требует наследования или реализации интерфейса. Вы можете увидеть это на примере ниже с Дюком ( Duke ) и Джагги ( Juggy ):
Вывод этого кода будет таким:
Так как определены конкретные реализации, то будут вызваны методы и Duke и Juggy .
Перегрузка (overloading) метода — это полиморфизм? Многие программисты путают отношение полиморфизма с переопределением методов (overriding) и перегрузкой методов (overloading). Фактически, только переопределение метода — это истинный полиморфизм. Перегрузка использует то же имя метода, но разные параметры. Полиморфизм — это широкий термин, поэтому всегда будут дискуссии на эту тему.
Какова цель полиморфизма
Большим преимуществом и целью использования полиморфизма является уменьшение связанности клиентского класса с реализацией. Вместо того чтобы хардкодить, клиентский класс получает реализацию зависимости для выполнения необходимого действия. Таким образом, клиентский класс знает минимум для выполнения своих действий, что является примером слабого связывания.
Чтобы лучше понять цель полиморфизма, взгляните на SweetCreator :
В этом примере вы можете видеть, что класс SweetCreator знает только о классе SweetProducer . Он не знает реализации каждого Sweet . Такое разделение дает нам гибкость для обновления и повторного использования наших классов, а это делает код намного проще в сопровождении. При проектировании кода всегда ищите способы сделать его максимально гибким и удобным. Полиморфизм — это очень мощный способ для использования в этих целях.
Ковариантные возвращаемые типы при переопределении метода
Можно изменить тип возвращаемого значения переопределенного метода если это ковариантный тип. Ковариантный тип в основном является подклассом возвращаемого значения.
Поскольку Duke является JavaMascot , мы можем изменить тип возвращаемого значения при переопределении.
Полиморфизм в базовых классах Java
Мы постоянно используем полиморфизм в базовых классах Java. Один очень простой пример — создание экземпляра класса ArrayList с объявлением типа как интерфейс List .
Рассмотрим пример кода, использующий Java Collections API без полиморфизма:
Отвратительный код, не так ли? Представьте себе, что вам нужно его сопровождать! Теперь рассмотрим тот же пример с полиморфизмом:
Преимущество полиморфизма — гибкость и расширяемость. Вместо того чтобы создавать несколько различных методов, мы можем объявить один метод, который получает тип List .
Вызов конкретных методов для полиморфного метода
Можно вызвать конкретные методы при полиморфном вызове метода, это происходит за счет гибкости. Вот пример:
Техника, которую мы используем здесь — это приведение типов (casting) или сознательное изменение типа объекта во время выполнения.
Обратите внимание, что вызов определенного метода возможен только при приведении более общего типа к более специфичному типу. Хорошей аналогией было бы сказать явно компилятору: «Эй, я знаю, что я здесь делаю, поэтому я собираюсь привести объект к определенному типу и буду использовать этот метод.»
Ссылаясь на приведенный выше пример, у компилятора есть веская причина не принимать вызов определенных методов: класс, который передаётся должен быть SolidSnake . В этом случае, у компилятора нет никакого способа гарантировать, что каждый подкласс MetalGearCharacter имеет метод giveOrderToTheArmy .
Ключевое слово instanceof
Обратите внимание на зарезервированное слово instanceof . Перед вызовом конкретного метода мы спросили, является ли MetalGearCharacter экземпляром (instanceof) BigBoss . Если это не экземпляр BigBoss , мы получим следующее исключение:
Ключевое слово super
Что делать, если мы хотим сослаться на атрибут или метод из родительского класса? В этом случае мы можем использовать ключевое слово super .
Например:
Использование зарезервированного слова super в методе executeAction класса Duke вызывает метод родительского класса. Затем мы выполняем конкретное действие из класса Duke . Вот почему мы можем видеть оба сообщения в выводе:
Решите задачку по полиморфизму
Давайте проверим, что вы узнали о полиморфизме и наследовании.
В этой задачке Вам дается несколько методов от Matt Groening’s The Simpsons, от вавам требуется разгадать, какой будет вывод для каждого класса. Для начала внимательно проанализируйте следующий код:
Как вы думаете? Каким будет результат? Не используйте IDE, чтобы выяснить это! Цель в том, чтобы улучшить ваши навыки анализа кода, поэтому постарайтесь решить самостоятельно.
Выберите ваш ответ (правильный ответ вы сможете найти в конце статьи).
A)
I love Sax!
D’oh
Simpson!
D’oh
B)
Sax 🙂
Eat my shorts!
I love Sax!
D’oh
Knock Homer down
C)
Sax 🙂
D’oh
Simpson!
Knock Homer down
D)
I love Sax!
Eat my shorts!
Simpson!
D’oh
Knock Homer down
Что случилось? Понимание полиморфизма
Для следующего вызова метода:
вывод будет «I love Sax!». Это потому, что мы передаём строку в метод и у класса Lisa есть такой метод.
Для следующего вызова:
Вывод будет «Eat my shorts!». Это потому, что мы инициализируем тип Simpson с помощью Bart .
Теперь смотрите, это немного сложнее:
Здесь мы используем перегрузку метода с наследованием. Мы ничего не передаем методу talk , поэтому вызывается метод talk из Simpson .
В этом случае на выходе будет «Simpson!».
В этом случае строка prank была передана при создании экземпляра класса Bart через new Bart(«D’oh»); . В этом случае сначала вызывается метод super.prank() , а затем метод prank() из класса Bart . Вывод будет:
Распространенные ошибки с полиморфизмом
Распространенная ошибка думать, что можно вызвать конкретный метод без использования приведения типа.
Другой ошибкой является неуверенность в том, какой метод будет вызван при полиморфном создании экземпляра класса. Помните, что вызываемый метод является методом созданного экземпляра.
Также помните, что переопределение метода не является перегрузкой метода.
Невозможно переопределить метод, если параметры отличаются. Можно изменить тип возвращаемого значения переопределенного метода, если возвращаемый тип является подклассом.
Что нужно помнить о полиморфизме
Созданный экземпляр определяет, какой метод будет вызван при использовании полиморфизма.
Аннотация @Override обязывает программиста использовать переопределенный метод; в противном случае возникнет ошибка компилятора.
Полиморфизм может использоваться с обычными классами, абстрактными классами и интерфейсами.
Большинство шаблонов проектирования зависят от той или иной формы полиморфизма.
Единственный способ вызвать нужный ваш метод в полиморфном подклассе — это использовать приведение типов.
Можно создать мощную структуру кода, используя полиморфизм.
Экспериментируйте. Через это, вы сможете овладеть этой мощной концепцией!
Ответ
Как всегда приветствую ваши комментарии и вопросы. И ждём у Виталия на открытом уроке.