Java Language
बहुरूपता
खोज…
परिचय
बहुरूपता मुख्य ओओपी (ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग) अवधारणाओं में से एक है। बहुरूपता शब्द ग्रीक शब्द "पॉली" और "मॉर्फ्स" से लिया गया था। पॉली का अर्थ है "कई" और मोर्फ्स का अर्थ है "रूप" (कई रूप)।
बहुरूपता प्रदर्शन करने के दो तरीके हैं। मेथड ओवरलोडिंग और मेथड ओवरराइडिंग ।
टिप्पणियों
कक्षा आधारित विरासत के अलावा, जावा में बहुरूपता को प्राप्त करने के लिए Interfaces
एक और तरीका है। इंटरफेस उन तरीकों की एक सूची को परिभाषित करते हैं जो कार्यक्रम का एपीआई बनाते हैं। कक्षाओं को अपने सभी तरीकों को ओवरराइड करके एक interface
implement
करना होगा।
विधि अतिभार
विधि अधिभार , जिसे फ़ंक्शन ओवरलोडिंग भी कहा जाता है, एक वर्ग की क्षमता है जिसमें एक ही नाम के साथ कई विधियां हैं, बशर्ते कि वे संख्या या प्रकार के तर्कों में भिन्न हों।
कंपाइलर विधि ओवरलोडिंग के लिए विधि हस्ताक्षर की जाँच करता है।
विधि हस्ताक्षर में तीन चीजें शामिल हैं -
- विधि का नाम
- मापदंडों की संख्या
- मापदंडों के प्रकार
यदि ये तीनों एक कक्षा में किसी भी दो तरीकों के लिए समान हैं, तो कंपाइलर डुप्लिकेट विधि त्रुटि को फेंकता है।
इस प्रकार के बहुरूपता को स्थैतिक या संकलित समय बहुरूपता कहा जाता है क्योंकि कहा जाने वाला उपयुक्त तरीका तर्क सूची के आधार पर संकलन समय के दौरान संकलक द्वारा तय किया जाता है।
class Polymorph {
public int add(int a, int b){
return a + b;
}
public int add(int a, int b, int c){
return a + b + c;
}
public float add(float a, float b){
return a + b;
}
public static void main(String... args){
Polymorph poly = new Polymorph();
int a = 1, b = 2, c = 3;
float d = 1.5, e = 2.5;
System.out.println(poly.add(a, b));
System.out.println(poly.add(a, b, c));
System.out.println(poly.add(d, e));
}
}
इसका परिणाम यह होगा:
2
6
4.000000
ओवरलोड तरीके स्थिर या गैर-स्थिर हो सकते हैं। यह भी विधि अधिभार प्रभाव नहीं करता है।
public class Polymorph {
private static void methodOverloaded()
{
//No argument, private static method
}
private int methodOverloaded(int i)
{
//One argument private non-static method
return i;
}
static int methodOverloaded(double d)
{
//static Method
return 0;
}
public void methodOverloaded(int i, double d)
{
//Public non-static Method
}
}
यदि आप रिटर्न प्रकार की विधि बदलते हैं, तो भी हम इसे ओवरलोडिंग विधि के रूप में प्राप्त करने में असमर्थ हैं।
public class Polymorph {
void methodOverloaded(){
//No argument and No return type
}
int methodOverloaded(){
//No argument and int return type
return 0;
}
विधि ओवरराइडिंग
ओवरराइडिंग विधि उनके सुपरपाइप्स के व्यवहार को फिर से परिभाषित करने (ओवरराइड) करने के लिए उपप्रकारों की क्षमता है।
जावा में, यह सुपर क्लास में परिभाषित तरीकों को ओवरराइड करने वाले उपवर्गों में अनुवाद करता है। जावा में, सभी गैर-आदिम चर वास्तव में references
, जो स्मृति में वास्तविक वस्तु के स्थान पर संकेत के समान हैं। references
केवल एक प्रकार होता है, जो वह प्रकार है जिसके साथ उन्हें घोषित किया गया था। हालांकि, वे अपने घोषित प्रकार या इसके किसी भी उपप्रकार के ऑब्जेक्ट को इंगित कर सकते हैं।
जब किसी विधि को एक reference
पर बुलाया जाता है, तो वास्तविक वस्तु की इसी विधि को इंगित किया जाता है ।
class SuperType {
public void sayHello(){
System.out.println("Hello from SuperType");
}
public void sayBye(){
System.out.println("Bye from SuperType");
}
}
class SubType extends SuperType {
// override the superclass method
public void sayHello(){
System.out.println("Hello from SubType");
}
}
class Test {
public static void main(String... args){
SuperType superType = new SuperType();
superType.sayHello(); // -> Hello from SuperType
// make the reference point to an object of the subclass
superType = new SubType();
// behaviour is governed by the object, not by the reference
superType.sayHello(); // -> Hello from SubType
// non-overridden method is simply inherited
superType.sayBye(); // -> Bye from SuperType
}
}
ध्यान रखने के नियम
उपवर्ग में एक विधि को ओवरराइड करने के लिए, ओवरराइडिंग विधि (यानी उपवर्ग में एक) का होना आवश्यक है :
- एक ही नाम
- प्राइमेटीज़ के मामले में एक ही रिटर्न प्रकार (वर्गों के लिए एक उपवर्ग की अनुमति है, इसे सहसंयोजक रिटर्न प्रकार के रूप में भी जाना जाता है)।
- एक ही प्रकार और मापदंडों का क्रम
- यह केवल उन अपवादों को फेंक सकता है जो सुपरक्लास की पद्धति के थ्रो क्लॉज में घोषित किए गए हैं या ऐसे अपवाद हैं जो घोषित अपवादों के उपवर्ग हैं। यह भी अपवाद नहीं फेंक करने के लिए चुन सकते हैं। पैरामीटर प्रकारों के नाम मायने नहीं रखते। उदाहरण के लिए, void methodX (int i) void methodX (int k) के समान है
- हम अंतिम या स्टेटिक विधियों को ओवरराइड करने में असमर्थ हैं। केवल एक चीज जो हम कर सकते हैं वह केवल विधि शरीर को बदल सकती है।
मौजूदा कोड को स्पर्श किए बिना कक्षाएं जोड़कर व्यवहार जोड़ना
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class PolymorphismDemo {
public static void main(String[] args) {
List<FlyingMachine> machines = new ArrayList<FlyingMachine>();
machines.add(new FlyingMachine());
machines.add(new Jet());
machines.add(new Helicopter());
machines.add(new Jet());
new MakeThingsFly().letTheMachinesFly(machines);
}
}
class MakeThingsFly {
public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
for (FlyingMachine flyingMachine : flyingMachines) {
flyingMachine.fly();
}
}
}
class FlyingMachine {
public void fly() {
out.println("No implementation");
}
}
class Jet extends FlyingMachine {
@Override
public void fly() {
out.println("Start, taxi, fly");
}
public void bombardment() {
out.println("Fire missile");
}
}
class Helicopter extends FlyingMachine {
@Override
public void fly() {
out.println("Start vertically, hover, fly");
}
}
व्याख्या
a) MakeThingsFly
वर्ग हर चीज के साथ काम कर सकता है जो कि प्रकार FlyingMachine
।
बी) विधि letTheMachinesFly
भी बिना किसी बदलाव के काम करती है (!) जब आप एक नया वर्ग जोड़ते हैं, उदाहरण के लिए PropellerPlane
:
public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
for (FlyingMachine flyingMachine : flyingMachines) {
flyingMachine.fly();
}
}
}
यही बहुरूपता की शक्ति है। आप इसके साथ खुले-बंद-सिद्धांत को लागू कर सकते हैं।
आभासी कार्य
वर्चुअल मेथड्स जावा में ऐसे तरीके हैं जो गैर-स्थैतिक हैं और सामने वाले कीवर्ड के बिना। जावा में डिफ़ॉल्ट रूप से सभी तरीके आभासी हैं। पॉलीमोर्फिज्म में वर्चुअल मेथड्स महत्वपूर्ण भूमिका निभाते हैं क्योंकि जावा में बच्चे वर्ग अपने माता-पिता की कक्षाओं के तरीकों को ओवरराइड कर सकते हैं यदि फ़ंक्शन को ओवरराइड किया जा रहा है तो वह गैर-स्टैटिक है और उसी तरीके के हस्ताक्षर हैं।
हालांकि, कुछ तरीके हैं जो आभासी नहीं हैं। उदाहरण के लिए, यदि विधि को निजी या कीवर्ड फाइनल के साथ घोषित किया जाता है, तो विधि आभासी नहीं है।
इस StackOverflow पोस्ट से वर्चुअल मेथड्स के साथ वंशानुक्रम के निम्नलिखित संशोधित उदाहरण पर विचार करें कि C # और Java में वर्चुअल फ़ंक्शंस कैसे काम करते हैं? :
public class A{
public void hello(){
System.out.println("Hello");
}
public void boo(){
System.out.println("Say boo");
}
}
public class B extends A{
public void hello(){
System.out.println("No");
}
public void boo(){
System.out.println("Say haha");
}
}
यदि हम कक्षा B को आह्वान करते हैं और हैलो () और बू () कहते हैं, तो हमें परिणामी आउटपुट के रूप में "नहीं" और "Say haha" मिलेगा क्योंकि B, A. से समान विधियों को ओवरराइड करता है, हालांकि उपरोक्त उदाहरण लगभग समान ही है ओवरराइड करने की विधि, यह समझना महत्वपूर्ण है कि कक्षा ए में विधियां डिफ़ॉल्ट रूप से, आभासी हैं।
इसके अतिरिक्त, हम अमूर्त कीवर्ड का उपयोग करके वर्चुअल तरीके लागू कर सकते हैं। कीवर्ड "अमूर्त" के साथ घोषित तरीकों में एक विधि परिभाषा नहीं है, जिसका अर्थ है कि विधि का शरीर अभी तक लागू नहीं हुआ है। बू () पद्धति को छोड़कर सार घोषित किए जाने के बाद फिर से ऊपर के उदाहरण पर विचार करें:
public class A{
public void hello(){
System.out.println("Hello");
}
abstract void boo();
}
public class B extends A{
public void hello(){
System.out.println("No");
}
public void boo(){
System.out.println("Say haha");
}
}
यदि हम B से बू () का आह्वान करते हैं, तब भी आउटपुट "Say haha" होगा क्योंकि B, एब्स्ट्रैक्ट मेथड boo () को इनहेरिट करता है और boo () आउटपुट "Say haha" बनाता है।
उपयोग किए गए और आगे पढ़ने के स्रोत:
वर्चुअल फ़ंक्शंस C # और Java में कैसे काम करते हैं?
आभासी कार्यों के बारे में बहुत अधिक संपूर्ण जानकारी देने वाले इस महान उत्तर को देखें:
क्या आप जावा में वर्चुअल फ़ंक्शंस / तरीके लिख सकते हैं?
बहुरूपता और विभिन्न प्रकार के ओवरराइडिंग
जावा ट्यूटोरियल से
बहुरूपता की शब्द परिभाषा जीव विज्ञान में एक सिद्धांत को संदर्भित करती है जिसमें एक जीव या प्रजाति के कई अलग-अलग रूप या चरण हो सकते हैं। इस सिद्धांत को ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग और जावा भाषा जैसी भाषाओं पर भी लागू किया जा सकता है। एक वर्ग के उपवर्ग अपने स्वयं के अनूठे व्यवहार को परिभाषित कर सकते हैं और फिर भी माता-पिता वर्ग की कुछ समान कार्यक्षमता को साझा कर सकते हैं।
विभिन्न प्रकार के ओवरराइडिंग को समझने के लिए इस उदाहरण को देखें।
- बेस क्लास कोई कार्यान्वयन प्रदान नहीं करता है और उप-वर्ग को पूरी विधि को ओवरराइड करना पड़ता है - (सार)
- बेस क्लास डिफ़ॉल्ट कार्यान्वयन प्रदान करता है और उप-वर्ग व्यवहार को बदल सकता है
- उप-वर्ग पहले कथन के रूप में
super.methodName()
कॉल करके बेस क्लास कार्यान्वयन में विस्तार जोड़ता है - बेस क्लास एल्गोरिथम (टेम्पलेट विधि) की संरचना को परिभाषित करता है और उप-वर्ग एल्गोरिथ्म के एक हिस्से को ओवरराइड करेगा
सांकेतिक टुकड़ा:
import java.util.HashMap;
abstract class Game implements Runnable{
protected boolean runGame = true;
protected Player player1 = null;
protected Player player2 = null;
protected Player currentPlayer = null;
public Game(){
player1 = new Player("Player 1");
player2 = new Player("Player 2");
currentPlayer = player1;
initializeGame();
}
/* Type 1: Let subclass define own implementation. Base class defines abstract method to force
sub-classes to define implementation
*/
protected abstract void initializeGame();
/* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
protected void logTimeBetweenMoves(Player player){
System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
}
/* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
super.methodName() in first line of the child class method and specific implementation later */
protected void logGameStatistics(){
System.out.println("Base class: logGameStatistics:");
}
/* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
protected void runGame() throws Exception{
System.out.println("Base class: Defining the flow for Game:");
while (runGame) {
/*
1. Set current player
2. Get Player Move
*/
validatePlayerMove(currentPlayer);
logTimeBetweenMoves(currentPlayer);
Thread.sleep(500);
setNextPlayer();
}
logGameStatistics();
}
/* sub-part of the template method, which define child class behaviour */
protected abstract void validatePlayerMove(Player p);
protected void setRunGame(boolean status){
this.runGame = status;
}
public void setCurrentPlayer(Player p){
this.currentPlayer = p;
}
public void setNextPlayer(){
if (currentPlayer == player1) {
currentPlayer = player2;
}else{
currentPlayer = player1;
}
}
public void run(){
try{
runGame();
}catch(Exception err){
err.printStackTrace();
}
}
}
class Player{
String name;
Player(String name){
this.name = name;
}
public String getName(){
return name;
}
}
/* Concrete Game implementation */
class Chess extends Game{
public Chess(){
super();
}
public void initializeGame(){
System.out.println("Child class: Initialized Chess game");
}
protected void validatePlayerMove(Player p){
System.out.println("Child class: Validate Chess move:" + p.getName());
}
protected void logGameStatistics(){
super.logGameStatistics();
System.out.println("Child class: Add Chess specific logGameStatistics:");
}
}
class TicTacToe extends Game{
public TicTacToe(){
super();
}
public void initializeGame(){
System.out.println("Child class: Initialized TicTacToe game");
}
protected void validatePlayerMove(Player p){
System.out.println("Child class: Validate TicTacToe move:" + p.getName());
}
}
public class Polymorphism{
public static void main(String args[]){
try{
Game game = new Chess();
Thread t1 = new Thread(game);
t1.start();
Thread.sleep(1000);
game.setRunGame(false);
Thread.sleep(1000);
game = new TicTacToe();
Thread t2 = new Thread(game);
t2.start();
Thread.sleep(1000);
game.setRunGame(false);
}catch(Exception err){
err.printStackTrace();
}
}
}
उत्पादन:
Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics: