java - पॉलिमॉर्फिज्म बनाम ओवरराइडिंग बनाम ओवरलोडिंग




oop polymorphism (14)

जावा के संदर्भ में, जब कोई पूछता है:

बहुरूपता क्या है?

ओवरलोडिंग या ओवरराइडिंग स्वीकार्य उत्तर होगा?

मुझे लगता है कि इसके मुकाबले थोड़ा और कुछ है।

यदि आपके पास एक सार आधार वर्ग था जिसने कोई कार्यान्वयन नहीं किया था, और आपने उप वर्ग में विधि को परिभाषित किया है, तो वह अभी भी ओवरराइड कर रहा है?

मुझे लगता है कि ओवरलोडिंग निश्चित रूप से सही जवाब नहीं है।


बहुरूपता क्या है?

जावा tutorial

बहुरूपता की शब्दकोश परिभाषा जीवविज्ञान में एक सिद्धांत को संदर्भित करती है जिसमें एक जीव या प्रजाति के कई अलग-अलग रूप या चरण हो सकते हैं। इस सिद्धांत को ऑब्जेक्ट उन्मुख प्रोग्रामिंग और जावा भाषा जैसी भाषाओं पर भी लागू किया जा सकता है। एक वर्ग के उप-वर्ग अपने स्वयं के अनूठे व्यवहार को परिभाषित कर सकते हैं और फिर भी अभिभावक वर्ग की समान कार्यक्षमता साझा कर सकते हैं।

उदाहरणों और परिभाषाओं पर विचार करके, ओवरराइडिंग को उत्तर स्वीकार किया जाना चाहिए।

आपकी दूसरी क्वेरी के बारे में:

यदि आपके पास एक सार आधार वर्ग था जिसने कोई कार्यान्वयन नहीं किया था, और आपने उप वर्ग में विधि को परिभाषित किया है, तो वह अभी भी ओवरराइड कर रहा है?

इसे ओवरराइडिंग कहा जाना चाहिए।

विभिन्न प्रकार के ओवरराइडिंग को समझने के लिए इस उदाहरण पर नज़र डालें।

  1. बेस क्लास कोई कार्यान्वयन प्रदान नहीं करता है और उप-वर्ग को पूर्ण विधि को ओवरराइड करना पड़ता है - (सार)
  2. बेस क्लास डिफ़ॉल्ट कार्यान्वयन प्रदान करता है और उप-वर्ग व्यवहार को बदल सकता है
  3. उप-वर्ग super.methodName() को पहले कथन के रूप में कॉल करके बेस क्लास कार्यान्वयन में विस्तार जोड़ता है
  4. बेस क्लास एल्गोरिदम (टेम्पलेट विधि) की संरचना को परिभाषित करता है और उप-वर्ग एल्गोरिदम के एक हिस्से को ओवरराइड करेगा

सांकेतिक टुकड़ा:

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:

अधिभार तब होता है जब आप एक ही नाम के साथ 2 विधियों को परिभाषित करते हैं लेकिन विभिन्न मानकों को परिभाषित करते हैं

ओवरराइडिंग वह जगह है जहां आप बेस क्लास के व्यवहार को उप-वर्ग में समान नाम वाले फ़ंक्शन के माध्यम से बदलते हैं।

तो पॉलिमॉर्फिज्म ओवरराइडिंग से संबंधित है लेकिन वास्तव में ओवरलोडिंग नहीं है।

हालांकि अगर किसी ने मुझे "पॉलिमॉर्फिज्म क्या है?" प्रश्न के लिए "ओवरराइडिंग" का एक सरल जवाब दिया है मैं आगे स्पष्टीकरण के लिए पूछूंगा।


आप सही हैं कि ओवरलोडिंग जवाब नहीं है।

न तो ओवरराइडिंग है। ओवरराइडिंग वह माध्यम है जिसके द्वारा आप बहुरूपता प्राप्त करते हैं। पॉलिमॉर्फिज्म एक वस्तु के प्रकार के आधार पर अलग-अलग व्यवहार करने की क्षमता है। यह सबसे अच्छा प्रदर्शन किया जाता है जब किसी ऑब्जेक्ट का कॉलर जो पॉलिमॉर्फिज्म प्रदर्शित करता है, इस बात से अनजान है कि ऑब्जेक्ट किस विशिष्ट प्रकार का है।


ओवरराइडिंग एक ही नाम और हस्ताक्षर के साथ ऊपरी स्तर विधि (सुपर विधि) के रूप में एक विधि घोषित करके विरासत विधि को छिपाने की तरह है, यह कक्षा में एक बहुलक व्यवहार जोड़ता है। दूसरे शब्दों में कहा जाने वाला विच स्तर विधि चुनने का निर्णय संकलन समय पर नहीं चलने पर किया जाएगा। यह इंटरफेस और कार्यान्वयन की अवधारणा की ओर जाता है।


छद्म-सी # / जावा में बहुरूपता का एक उदाहरण यहां दिया गया है:

class Animal
{
    abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
        return "Meow";
    }
}

class Dog : Animal {
    string MakeNoise () {
        return "Bark";
    }
}

Main () {
   Animal animal = Zoo.GetAnimal ();
   Console.WriteLine (animal.MakeNoise ());
}

मुख्य कार्य जानवर के प्रकार को नहीं जानता है और MakeNoise () विधि के किसी विशेष कार्यान्वयन के व्यवहार पर निर्भर करता है।

संपादित करें: ऐसा लगता है जैसे ब्रायन ने मुझे पंच पर मार दिया। मजेदार हम एक ही उदाहरण का इस्तेमाल किया। लेकिन उपरोक्त कोड अवधारणाओं को स्पष्ट करने में मदद करनी चाहिए।


जब हम बेस क्लास का उत्तराधिकारी बनाते हैं और व्युत्पन्न कक्षा बनाते हैं तो यदि व्युत्पन्न कक्षा में एक विधि होती है जिसमें विधि के समान नाम होता है (समान नाम, एक ही तर्क, समान वापसी प्रकार) बेस क्लास में परिभाषित किया जाता है तो इसे ओवरराइडिंग कहा जाता है ..

  class Vehicle{  
      void run()
          {
           System.out.println("Vehicle is running");
          }  
               }
   class Bike2 extends Vehicle{  
       void run()
           {
            System.out.println("Bike is running safely");
           }  

    public static void main(String args[]){  
    Bike2 obj = new Bike2();  
    obj.run();  
     }  

आउटपुट: बाइक सुरक्षित रूप से चल रहा है ........ अधिक स्पष्ट रूप से ओवरराइडिंग को समझने के लिए यहां जाएं: http://javabyroopam.blogspot.in/

ओवरलोडिंग केवल दो विधियों के समान नाम हैं लेकिन अलग-अलग तर्क सूची है जिसे ओवरलोडिंग कहा जाता है ..

   class Calculation{  
      void sum(int a,int b){System.out.println(a+b);}  
      void sum(int a,int b,int c){System.out.println(a+b+c);}  

      public static void main(String args[]){  
      Calculation obj=new Calculation();  
      obj.sum(10,10,10);  
       obj.sum(20,20);  

       }  
    }  

आउटपुट 30,20


न तो:

ओवरलोडिंग तब होती है जब आपके पास एक ही फ़ंक्शन नाम होता है जो विभिन्न पैरामीटर लेता है।

ओवरराइडिंग तब होती है जब एक बच्चा वर्ग माता-पिता की विधि को अपने आप में से एक के साथ बदल देता है (यह स्वयं में बहुरूपता का गठन नहीं करता है)।

पॉलिमॉर्फिज्म देर से बाध्यकारी है, उदाहरण के लिए बेस क्लास (पैरेंट) विधियों को बुलाया जा रहा है, लेकिन रनटाइम तक नहीं, एप्लिकेशन को पता है कि वास्तविक वस्तु क्या है - यह एक बाल वर्ग हो सकता है जिसका विधियां अलग हैं। ऐसा इसलिए है क्योंकि किसी भी वर्ग वर्ग का उपयोग किया जा सकता है जहां बेस क्लास परिभाषित किया जाता है।

जावा में आप संग्रह पुस्तकालय के साथ बहुरूपता देखते हैं:

int countStuff(List stuff) {
  return stuff.size();
}

सूची बेस क्लास है, यदि आप एक लिंक्ड सूची, वेक्टर, सरणी, या एक कस्टम सूची कार्यान्वयन की गणना कर रहे हैं, तब तक संकलक के पास कोई सुराग नहीं है, जब तक यह एक सूची की तरह कार्य करता है:

List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);

यदि आप ओवरलोडिंग कर रहे थे तो आपके पास होगा:

int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...

और पैरामीटर से मेल खाने के लिए कंपाइलर द्वारा गिनस्टफ () का सही संस्करण चुना जाएगा।


पॉलिमॉर्फिज्म एक भाषा की क्षमता से संबंधित है जो अलग-अलग ऑब्जेक्ट का उपयोग करके एक ही इंटरफेस का उपयोग करके समान रूप से व्यवहार किया जाता है; चूंकि यह ओवरराइडिंग से संबंधित है, इसलिए इंटरफेस (या बेस क्लास) पॉलिमॉर्फिक है, कार्यान्वयनकर्ता वह वस्तु है जो ओवरराइड करता है (उसी पदक के दो चेहरे)

वैसे भी, दो शर्तों के बीच का अंतर अन्य भाषाओं का उपयोग करके बेहतर समझाया गया है, जैसे सी ++: सी ++ में एक पॉलिमॉर्फिक ऑब्जेक्ट जावा काउंटरपार्ट के रूप में व्यवहार करता है यदि आधार फ़ंक्शन वर्चुअल है, लेकिन यदि विधि वर्चुअल नहीं है तो कोड कूद स्थिर रूप से हल हो जाती है, और रनटाइम पर सही प्रकार की जांच नहीं की जाती है, इसलिए पॉलिमॉर्फिज्म में किसी ऑब्जेक्ट को अलग-अलग व्यवहार करने की क्षमता शामिल होती है जो इसे एक्सेस करने के लिए उपयोग किए जाने वाले इंटरफ़ेस के आधार पर भिन्न होती है; मुझे छद्म कोड में एक उदाहरण दें:

class animal {
    public void makeRumor(){
        print("thump");
    }
}
class dog extends animal {
    public void makeRumor(){
        print("woff");
    }
}

animal a = new dog();
dog b = new dog();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

(लगता है कि makeRumor आभासी नहीं है)

जावा वास्तव में बहुरूपता के इस स्तर की पेशकश नहीं करता है (जिसे ऑब्जेक्ट स्लाइसिंग भी कहा जाता है)।

पशु ए = नया कुत्ता (); कुत्ता बी = नया कुत्ता ();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

दोनों स्थितियों में यह केवल woff प्रिंट करेगा .. चूंकि ए और बी कक्षा कुत्ते को प्रतिबिंबित कर रहा है


पॉलिमॉर्फिज्म का मतलब एक से अधिक रूप है, वही वस्तु आवश्यकता के अनुसार विभिन्न परिचालन कर रही है।

पॉलिमॉर्फिज्म दो तरीकों से उपयोग करके हासिल किया जा सकता है, वे हैं

  1. विधि ओवरराइडिंग
  2. विधि ओवरलोडिंग

विधि अधिभार का मतलब समान विधि नाम का उपयोग करके एक ही कक्षा में दो या दो से अधिक विधियों को लिखना है, लेकिन गुजरने वाले पैरामीटर अलग हैं।

विधि ओवरराइडिंग का अर्थ है कि हम अलग-अलग वर्गों में विधि नामों का उपयोग करते हैं, इसका मतलब है कि बाल वर्ग में मूल वर्ग विधि का उपयोग किया जाता है।

पॉलिमॉर्फिज्म प्राप्त करने के लिए जावा में एक सुपर क्लास संदर्भ चर उप वर्ग ऑब्जेक्ट को पकड़ सकता है।

बहुरूपता प्राप्त करने के लिए प्रत्येक डेवलपर को परियोजना में समान विधि नामों का उपयोग करना होगा।


पॉलिमॉर्फिज्म किसी ऑब्जेक्ट का एक से अधिक कार्यान्वयन है या आप ऑब्जेक्ट के कई रूपों को कह सकते हैं। मान लें कि आपके पास क्लास Animals को सार आधार वर्ग के रूप में रखा गया है और इसमें movement() नामक एक विधि है जो जानवर को आगे बढ़ने के तरीके को परिभाषित करती है। अब हकीकत में हमारे पास विभिन्न प्रकार के जानवर हैं और वे अलग-अलग होते हैं, साथ ही उनमें से कुछ 2 पैरों के साथ, दूसरों के साथ 4 और कुछ पैरों के साथ आदि .. पृथ्वी पर प्रत्येक जानवर के विभिन्न movement() को परिभाषित करने के लिए, हमें आवेदन करने की आवश्यकता है बहुरूपता। हालांकि, आपको अधिक कक्षाओं यानी कक्षा Dogs Cats Fish आदि को परिभाषित करने की आवश्यकता है। फिर आपको उन वर्गों को बेस क्लास Animals से विस्तारित करने और अपने प्रत्येक गतिविधि के आधार पर एक नई आवागमन कार्यक्षमता के साथ अपनी विधि movement() को ओवरराइड करने की आवश्यकता है। आप इसे प्राप्त करने के लिए Interfaces का भी उपयोग कर सकते हैं। यहां का कीवर्ड ओवरराइडिंग है, ओवरलोडिंग अलग है और इसे पॉलिमॉर्फिज्म के रूप में नहीं माना जाता है। ओवरलोडिंग के साथ आप "समान नाम के साथ" कई विधियों को परिभाषित कर सकते हैं लेकिन एक ही ऑब्जेक्ट या क्लास पर विभिन्न पैरामीटर के साथ।


पॉलीमोर्फिज्म एक वस्तु के कई रूपों में प्रकट होने की क्षमता है। इसमें वस्तुओं का एक परिवार बनाने के लिए विरासत और वर्चुअल फ़ंक्शंस का उपयोग करना शामिल है जिसे इंटरचेंज किया जा सकता है। बेस क्लास में वर्चुअल फ़ंक्शंस का प्रोटोटाइप होता है, संभवतः अनुपूरक या डिफ़ॉल्ट कार्यान्वयन के साथ-साथ एप्लिकेशन निर्देशित करता है, और विभिन्न व्युत्पन्न कक्षाएं प्रत्येक अलग-अलग व्यवहारों को प्रभावित करने के लिए अलग-अलग लागू करती हैं।


बहुरूपता व्यक्त करने का सबसे स्पष्ट तरीका एक सार आधार वर्ग (या इंटरफेस) के माध्यम से है

public abstract class Human{
   ...
   public abstract void goPee();
}

यह वर्ग अमूर्त है क्योंकि goPee() विधि मानवों के लिए निश्चित नहीं है। यह उप-वर्ग पुरुष और महिला के लिए केवल निश्चित है। इसके अलावा, मानव एक अमूर्त अवधारणा है - आप ऐसे मनुष्य को नहीं बना सकते जो न तो नर और न ही महिला है। यह एक या दूसरे होना चाहिए।

इसलिए हम अमूर्त वर्ग का उपयोग करके कार्यान्वयन को रोकते हैं।

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

तथा

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

अब हम पीस जाने के लिए मनुष्यों से भरे पूरे कमरे को बता सकते हैं।

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

इसे चलाने से उपज होगी:

Stand Up
Sit Down
...

विशेष रूप से ओवरलोडिंग या ओवरराइडिंग कहने से पूर्ण तस्वीर नहीं मिलती है। पॉलिमॉर्फिज्म बस अपने प्रकार के आधार पर अपने व्यवहार को विशेषज्ञता देने के लिए एक वस्तु की क्षमता है।

मैं यहां कुछ जवाबों से असहमत हूं कि ओवरलोडिंग पॉलिमॉर्फिज्म (पैरामीट्रिक पॉलिमॉर्फिज्म) का एक रूप है, इस मामले में एक ही नाम वाली विधि अलग-अलग पैरामीटर प्रकारों को अलग तरीके से व्यवहार कर सकती है। एक अच्छा उदाहरण ऑपरेटर ओवरलोडिंग है। आप विभिन्न प्रकार के पैरामीटर स्वीकार करने के लिए "+" को परिभाषित कर सकते हैं - स्ट्रिंग्स या इंट कहते हैं - और उन प्रकारों के आधार पर, "+" अलग-अलग व्यवहार करेगा।

पॉलिमॉर्फिज्म में विरासत और ओवरराइडिंग विधियां भी शामिल हैं, हालांकि वे मूल प्रकार में सार या आभासी हो सकते हैं। विरासत-आधारित बहुरूपता के संदर्भ में, जावा केवल एकल वर्ग विरासत का समर्थन करता है जो इसे पॉलिमॉर्फिक व्यवहार को आधार प्रकारों की एक श्रृंखला के लिए सीमित करता है। जावा कई इंटरफेस के कार्यान्वयन का समर्थन करता है जो अभी तक पॉलिमॉर्फिक व्यवहार का एक और रूप है।


पॉलिमॉर्फिज्म एक वर्ग के उदाहरण की व्यवहार करने की क्षमता है जैसे कि यह अपने विरासत के पेड़ में एक और वर्ग का उदाहरण था, जो प्रायः अपने पूर्वजों के वर्गों में से एक था। उदाहरण के लिए, जावा में सभी वर्ग ऑब्जेक्ट से प्राप्त होते हैं। इसलिए, आप ऑब्जेक्ट प्रकार का एक चर बना सकते हैं और किसी भी वर्ग के उदाहरण को असाइन कर सकते हैं।

एक ओवरराइड एक प्रकार का फ़ंक्शन होता है जो किसी वर्ग में होता है जो किसी अन्य वर्ग से प्राप्त होता है। एक ओवरराइड फ़ंक्शन बेस क्लास से विरासत में प्राप्त एक फ़ंक्शन को "प्रतिस्थापित करता है", लेकिन ऐसा इसलिए करता है कि इसे तब भी कहा जाता है जब इसकी कक्षा का एक उदाहरण बहुरूपता के माध्यम से एक अलग प्रकार का नाटक कर रहा है। पिछले उदाहरण का जिक्र करते हुए, आप अपनी खुद की कक्षा को परिभाषित कर सकते हैं और toString () फ़ंक्शन को ओवरराइड कर सकते हैं। चूंकि यह फ़ंक्शन ऑब्जेक्ट से विरासत में मिला है, फिर भी यह तब भी उपलब्ध होगा जब आप इस वर्ग का एक ऑब्जेक्ट-ऑब्जेक्ट-वेरिएबल में प्रतिलिपि बनाते हैं। आम तौर पर, यदि आप ऑब्जेक्ट होने का नाटक करते समय अपनी कक्षा में टूस्ट्रिंग () को कॉल करते हैं, तो स्ट्रिंग का संस्करण जो वास्तव में आग लगाएगा वह ऑब्जेक्ट पर परिभाषित किया गया है। हालांकि, क्योंकि फ़ंक्शन एक ओवरराइड है, आपकी कक्षा से ToString () की परिभाषा तब भी उपयोग की जाती है जब क्लास इंस्टेंस का वास्तविक प्रकार बहुरूपता के पीछे छिपा हुआ होता है।

ओवरलोडिंग एक ही नाम के साथ कई विधियों को परिभाषित करने की क्रिया है, लेकिन विभिन्न मानकों के साथ। यह या तो ओवरराइडिंग या पॉलिमॉर्फिज्म से असंबंधित है।





override