क्या जावा में वर्ग चर को ओवरराइड करने का एक तरीका है?


161
class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";
}

public void doIt()
{
    new Son().printMe();
}

फ़ंक्शन doIt "पिता" मुद्रित करेगा। क्या इसे "बेटा" छापने का कोई तरीका है?


111
यदि आप कभी भी संरक्षित स्थैतिक देखते हैं, तो दौड़ें।
टॉम हॉल्टिन -

23
@ टॉमहॉटिन-टैकलिन ने मेरी अज्ञानता को माफ कर दिया, लेकिन एक संरक्षित स्थैतिक को क्यों पराजित किया गया है? मैंने गुगली करने की कोशिश की, लेकिन स्पष्ट जवाब नहीं मिला। साभार
टोनी चैन

जवाबों:


68

हाँ। लेकिन जैसा कि वैरिएबल का संबंध है यह ओवरराइट है (वैरिएबल को नया मान देते हुए। फंक्शन को नई परिभाषा देना ओवरराइड है)।Just don't declare the variable but initialize (change) in the constructor or static block.

मूल वर्ग के ब्लॉक में उपयोग करते समय मान परिलक्षित होगा

यदि वैरिएबल स्थिर है तो स्थैतिक ब्लॉक के साथ इनिशियलाइज़ेशन के दौरान मान को बदलें,

class Son extends Dad {
    static { 
       me = 'son'; 
    }
}

या कंस्ट्रक्टर में बदलाव।

आप बाद में किसी भी ब्लॉक में मान बदल सकते हैं। यह सुपर क्लास में परिलक्षित होगा


10
मुझे लगता है कि जवाब में बेहतर पठनीयता के लिए कुछ कोड होना चाहिए। बस बेटे के कार्यान्वयन को बदल दें class Son extends Dad { static { me = 'son' } }
क्लेसीओ मेंडेस

97

संक्षेप में, नहीं, वर्ग चर को ओवरराइड करने का कोई तरीका नहीं है।

आप जावा में वर्ग चर को ओवरराइड नहीं करते हैं आप उन्हें छिपाते हैं। उदाहरण के तरीकों के लिए ओवरराइडिंग है। छिपाना ओवरराइडिंग से अलग है।

आपके द्वारा दिए गए उदाहरण में, वर्ग चर को 'me' नाम से घोषित करके पुत्र में आप वर्ग चर को छिपाते हैं, जो उसके सुपरक्लास डैड को उसी नाम 'me' से विरासत में मिला होगा। इस तरह से एक वैरिएबल को छुपाने से सुपरक्लास डैड में क्लास वेरिएबल 'मी' का मूल्य प्रभावित नहीं होता है।

आपके प्रश्न के दूसरे भाग के लिए, इसे "बेटा" कैसे प्रिंट करना है, मैं कंस्ट्रक्टर के माध्यम से मान सेट करूँगा। हालाँकि नीचे दिया गया कोड आपके मूल प्रश्न से काफी दूर जाता है, मैं इसे कुछ इस तरह लिखूंगा;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println(name);
    }
}

JLS खंड 8.3 - क्षेत्र घोषणाओं में छिपाने पर बहुत अधिक विवरण देता है


1
व्युत्पन्न वर्ग में एक स्थिर ब्लॉक होने से ओवरराइड संभव है
siddagrl

1
@ सिद्धिगर्ल: क्या आप विस्तृत कर सकते हैं?
Mr_and_Mrs_D

Personइस उदाहरण में ओपी की कौन सी कक्षा को प्रतिस्थापित करना है?
n611x007

1
@naxa Sonऔर Dadमाना जाता है कि इनसे विरासत में मिली है Person, फिर super("Son or Dad");अपने निर्माणकर्ताओं को बुलाओ ।
पैनजेरक्रिस

क्या जावा में चर को छुपाना अच्छा या बुरा माना जाता है?
पैनजेरक्रिस

31

हां, बस printMe()विधि को ओवरराइड करें :

class Son extends Dad {
        public static final String me = "son";

        @Override
        public void printMe() {
                System.out.println(me);
        }
}

क्या होगा यदि आप जो पुस्तकालय उपयोग कर रहे हैं printMe(), उसमें विधि नहीं है , या यहां तक ​​कि यह विधि है कि यह एक स्थिर विधि है?
वेंकट सुधीर रेड्डी एडेमा

1
इसे और अधिक वास्तविक जीवन उदाहरण बनाने के लिए, आप विचार कर सकते हैं कि "PrintMe" विधि तर्क के साथ एक बहुत ही जटिल कार्य हो सकता है जिसे आप दोहराना नहीं चाहते हैं। इस उदाहरण में, आप केवल व्यक्ति का नाम बदलना चाहते हैं, न कि उस तर्क को जो उसे प्रिंट करता है। आपको "getName" नामक एक विधि बनानी चाहिए जिसे आप "बेटा" वापस करने के लिए ओवरराइड करेंगे और प्रिंटमे विधि getName विधि को उसकी छपाई के हिस्से के रूप में लागू करेगी।
रिंग

17

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

class Dad
{
        private static final String me = "dad";

        protected String getMe() {
            return me;
        }

        public void printMe()
        {
                System.out.println(getMe());
        }
}

class Son extends Dad
{
        private static final String me = "son";

        @Override
        protected String getMe() {
            return me;
        }
}

public void doIt()
{
        new Son().printMe(); //Prints "son"
}

11

यदि आप इसे ओवरराइड करने जा रहे हैं तो मुझे इस स्थैतिक को रखने का कोई वैध कारण नहीं दिखता है। मैं अमूर्त के उपयोग का सुझाव दूंगा (उदाहरण कोड देखें)। :

     public interface Person {
        public abstract String getName();
       //this will be different for each person, so no need to make it concrete
        public abstract void setName(String name);
    }

अब हम पिताजी को जोड़ सकते हैं:

public class Dad implements Person {

    private String name;

    public Dad(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
    return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

बेटा:

public class Son implements Person {

    private String name;

    public Son(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

और पिताजी एक अच्छी महिला से मिले:

public class StepMom implements Person {

    private String name;

    public StepMom(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

ऐसा लगता है जैसे हमारा परिवार है, दुनिया को उनके नाम बताते हैं:

public class ConsoleGUI {

    public static void main(String[] args) {
        List<Person> family = new ArrayList<Person>();
        family.add(new Son("Tommy"));
        family.add(new StepMom("Nancy"));
        family.add(new Dad("Dad"));
        for (Person person : family) {
            //using the getName vs printName lets the caller, in this case the
            //ConsoleGUI determine versus being forced to output through the console. 
            System.out.print(person.getName() + " ");
            System.err.print(person.getName() + " ");
            JOptionPane.showMessageDialog(null, person.getName());
    }
}

}

System.out आउटपुट: टॉमी नैन्सी पिताजी
System.err उपर्युक्त जैसा ही है (बस लाल फ़ॉन्ट है)
JOption आउटपुट:
टॉमी तो
नैन्सी तो
पिताजी


1
ओपी स्टैटिक्स तक पहुंच को बदलने के बारे में था। इसलिए "मुझे" एक सामान्य "डैड" या "बेटा" था - ऐसा कुछ जो हर पिता या पुत्र के लिए बनाने की आवश्यकता नहीं है और इसलिए एक स्थिर है।
रिचीएच

हाँ, आपका अधिकार, मैंने नहीं देखा कि यह स्थिर था। हाहा, जो मेरे उत्तर को कोड की लगभग 100 कम लाइनों में बदल देगा, यदि सभी पर उत्तर दिया गया है। सिर के लिए धन्यवाद
nckbrz

6

यह एक डिजाइन दोष की तरह दिखता है।

स्थिर कीवर्ड निकालें और कंस्ट्रक्टर में उदाहरण के लिए चर सेट करें। इस तरह से सोन अपने वेरिएबल में वेरिएबल को एक अलग वैल्यू पर सेट करता है।


1
इस बारे में क्या गलत है? अगर 'me' मेंबर वेरिएबल को आपके डिजाइन में ओवरएडेबल माना जाता है, तो पेट्रिक का सही समाधान है
Chii

दरअसल, अगर हर उदाहरण के लिए मेरा मूल्य समान है, तो 'स्टैटिक' को हटा देना ही ठीक रहेगा। प्रारंभिक निर्माण में नहीं होना चाहिए।
नैट पार्सन्स

ठीक है, हालांकि तकनीकी रूप से (bytecode में) मुझे लगता है कि यह लगभग एक ही है ;-)
पैट्रिक कॉर्नेलिसन

4

हालांकि यह सच है कि वर्ग चर केवल उपवर्गों में छिपे हो सकते हैं, और ओवरराइड नहीं किए जा सकते हैं, फिर भी यह करना संभव है कि आप printMe ()उपवर्गों में ओवरराइड किए बिना क्या चाहते हैं , और प्रतिबिंब आपका मित्र है। नीचे दिए गए कोड में मैं स्पष्टता के लिए अपवाद हैंडलिंग को छोड़ देता हूं। कृपया ध्यान दें कि घोषित करने meके रूप में protected, इस संदर्भ में ज्यादा मतलब नहीं है प्रतीत नहीं होता है के रूप में यह उपवर्गों में छिपा होने जा रही है ...

class Dad
  {
    static String me = "dad";

    public void printMe ()
      {
        java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
        System.out.println (field.get (null));
      }
  }

बहुत दिलचस्प, Java.lang.reflect हुह? ... +1
nckbrz

3
class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String _me = me = "son";
}

public void doIt()
{
    new Son().printMe();
}

... "बेटा" छापेंगे।


क्या यह मूल प्रश्न जैसा नहीं है?
Corley Brigman

क्या आप व्यख्या कर सकते हैं ? (आपके उत्तर में)
Mr_and_Mrs_D

3

https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html

इसे हाइडिंग फील्ड्स कहा जाता है

ऊपर दिए गए लिंक से

एक वर्ग के भीतर, एक क्षेत्र जिसमें सुपरक्लास के एक क्षेत्र के समान नाम है, सुपरक्लास के क्षेत्र को छुपाता है, भले ही उनके प्रकार अलग हों। उपवर्ग के भीतर, सुपरक्लास के क्षेत्र को उसके सरल नाम से संदर्भित नहीं किया जा सकता है। इसके बजाय, फ़ील्ड को सुपर के माध्यम से एक्सेस किया जाना चाहिए, जो अगले अनुभाग में कवर किया गया है। सामान्यतया, हम फ़ील्ड को छिपाने की अनुशंसा नहीं करते क्योंकि यह कोड को पढ़ना मुश्किल बनाता है।


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

2

केवल ओवरराइड करके printMe():

class Son extends Dad 
{
    public void printMe() 
    {
        System.out.println("son");
    }
}

के संदर्भ meमें Dad.printMeस्थिर क्षेत्र के लिए विधि परोक्ष अंक Dad.meतो एक ही रास्ता है, या किसी अन्य आप बदल रहे हैं क्या printMeमें है Son...


2

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


आप किसी भी स्टैटिक्स को ओवरराइड नहीं कर सकते।
टॉम हॉल्टिन - 11:26 बजे

(या कम से कम यह समझ में नहीं आता है, IFSWIM।)
टॉम हॉकिन -

सही है, आप स्टैटिक्स को ओवरराइड नहीं कर सकते। आप उन्हें या कुछ लोगों ने मुझे MASKING कह सकते हैं।
डेल

2

यह वास्तव में 'डैड' को प्रिंट करता है, क्योंकि यह क्षेत्र ओवरराइड नहीं है, लेकिन छिपा हुआ है। इसे 'बेटा' छापने के तीन तरीके हैं:

दृष्टिकोण 1: प्रिंटमे को ओवरराइड करें

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";

    @override
    public void printMe()
    {
        System.out.println(me);
    }
}

public void doIt()
{
    new Son().printMe();
}

दृष्टिकोण 2: क्षेत्र को छिपाएं नहीं और इसे प्रारंभ करें

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    public Son()
    {
        me = "son";
    }
}

public void doIt()
{
    new Son().printMe();
}

दृष्टिकोण 3: कंस्ट्रक्टर में किसी फ़ील्ड को इनिशियलाइज़ करने के लिए स्टैटिक वैल्यू का उपयोग करें

class Dad
{
    private static String meInit = "Dad";

    protected String me;

    public Dad() 
    {
       me = meInit;
    }

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    private static String meInit = "son";

    public Son()
    {
        me = meInit;
    }

}

public void doIt()
{
    new Son().printMe();
}

2

चर ओवरराइडिंग में भाग नहीं लेते हैं। केवल विधियाँ करते हैं। एक विधि कॉल रनटाइम पर हल की जाती है, अर्थात, कॉल करने का निर्णय रनटाइम पर लिया जाता है, लेकिन चर का संकलन समय पर ही किया जाता है। इसलिए उस चर को कहा जाता है जिसका संदर्भ कॉलिंग के लिए उपयोग किया जाता है न कि रनटाइम ऑब्जेक्ट के लिए।

निम्नलिखित स्निपेट पर एक नज़र डालें:

package com.demo;

class Bike {
  int max_speed = 90;
  public void disp_speed() {
    System.out.println("Inside bike");
 }
}

public class Honda_bikes extends Bike {
  int max_speed = 150;
  public void disp_speed() {
    System.out.println("Inside Honda");
}

public static void main(String[] args) {
    Honda_bikes obj1 = new Honda_bikes();
    Bike obj2 = new Honda_bikes();
    Bike obj3 = new Bike();

    obj1.disp_speed();
    obj2.disp_speed();
    obj3.disp_speed();

    System.out.println("Max_Speed = " + obj1.max_speed);
    System.out.println("Max_Speed = " + obj2.max_speed);
    System.out.println("Max_Speed = " + obj3.max_speed);
  }

}

जब आप कोड चलाते हैं, तो कंसोल दिखाएगा:

Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90

0

बेशक निजी विशेषताओं का उपयोग कर, और गेटर्स और सेटर करने की सिफारिश की जाएगी, लेकिन मैंने निम्नलिखित का परीक्षण किया, और यह काम करता है ... कोड में टिप्पणी देखें

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";

    /* 
    Adding Method printMe() to this class, outputs son 
    even though Attribute me from class Dad can apparently not be overridden
    */

    public void printMe()
    {
        System.out.println(me);
    }
}

class Tester
{
    public static void main(String[] arg)
    {
        new Son().printMe();
    }
}

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


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

आप प्रोग्रामिंग को अकेले कोडिंग के नजरिए से देख रहे हैं। जो ठीक है, उस मामले में आप चाहते हैं, हालांकि कोड। यदि आप एक टीम के सदस्य के दृष्टिकोण से कोडिंग को देखते हैं, तो नियम स्पष्ट हो जाते हैं, जैसे कि फ़ील्ड अति-योग्य और इतने पर क्यों नहीं हैं। मैं आपको ऐसा करने के लिए एक भाषण दे सकता हूं, लेकिन यदि आप इसे टीम के सदस्य के दृष्टिकोण से नहीं देख रहे हैं, तो आप मेरे बिंदुओं को अमान्य मानेंगे और अमान्य तर्क मुझ पर वापस फेंक देंगे।
nckbrz

0

जब आप आसानी से उपक्लेसेस में उन्हें पुन: असाइन कर सकते हैं तो आप चर को ओवरराइड क्यों करना चाहेंगे।

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

public interface ExtensibleService{
void init();
}

public class WeightyLogicService implements ExtensibleService{
    private String directoryPath="c:\hello";

    public void doLogic(){
         //never forget to call init() before invocation or build safeguards
         init();
       //some logic goes here
   }

   public void init(){}    

}

public class WeightyLogicService_myAdaptation extends WeightyLogicService {
   @Override
   public void init(){
    directoryPath="c:\my_hello";
   }

}

0

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

बेटा बढ़ाता है डैड ह्यूमन बढ़ाता है

नीचे दिए गए कोड में, हम मानव, पिता और पुत्र वस्तुओं की एक सरणी पर पुनरावृति करने की कोशिश करते हैं, लेकिन यह सभी मामलों में मानव वर्ग के मूल्यों को प्रिंट करता है क्योंकि कॉलिंग ऑब्जेक्ट का प्रकार मानव था।

    class Human
{
    static String me = "human";

    public void printMe()
    {
        System.out.println(me);
    }
}
class Dad extends Human
{
    static String me = "dad";

}

class Son extends Dad
{
    static String me = "son";
}


public class ClassVariables {
    public static void main(String[] abc)   {
        Human[] humans = new Human[3];
        humans[0] = new Human();
        humans[1] = new Dad();
        humans[2] = new Son();
        for(Human human: humans)   {
            System.out.println(human.me);        // prints human for all objects
        }
    }
}

छपेगा

  • मानव
  • मानव
  • मानव

इसलिए कक्षा चर का कोई ओवरराइडिंग नहीं।

यदि हम वास्तविक वस्तु के वर्ग चर को उसके मूल वर्ग के संदर्भ चर से एक्सेस करना चाहते हैं, तो हमें इसके प्रकार को स्पष्ट रूप से जनक संदर्भ (मानव वस्तु) को टाइप करके संकलक को बताना होगा।

    System.out.println(((Dad)humans[1]).me);        // prints dad

    System.out.println(((Son)humans[2]).me);        // prints son

छपेगा

  • पिता
  • बेटा

इस प्रश्न के किस भाग पर: - जैसा कि पहले ही सुझाव दिया गया है कि बेटा वर्ग में प्रिंटम () विधि को ओवरराइड करें, फिर कॉलिंग पर

Son().printMe();

पिताजी की कक्षा चर "मुझे" छिपा दिया जाएगा क्योंकि "मी" (सोन वर्ग में) के निकटतम घोषणा (सोन वर्ग प्रिंटमे () विधि से) को पूर्वता मिल जाएगी।


0

सुपर क्लास कंस्ट्रक्टर में सुपर कॉल करें

public abstract class Beverage {

int cost;


int getCost() {

    return cost;

}

}`

public class Coffee extends Beverage {


int cost = 10;
Coffee(){
    super.cost = cost;
}


}`

public class Driver {

public static void main(String[] args) {

    Beverage coffee = new Coffee();

    System.out.println(coffee.getCost());

}

}

आउटपुट 10 है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.