java - जावा स्थिर तरीकों को ओवरराइड करने की अनुमति क्यों नहीं देता है?




static override (15)

स्थिर तरीकों को ओवरराइड करना क्यों संभव नहीं है?

यदि संभव हो, तो कृपया एक उदाहरण का प्रयोग करें।


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

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

परिणाम का परिणाम:

0.02
0.02
0.02
0.03

हम क्या हासिल करने की कोशिश कर रहे थे :)

भले ही हम तीसरे चर कार्ल को RegularEmployee के रूप में घोषित करते हैं और इसे विशेष कर्मचारी के उदाहरण को आवंटित करते हैं, फिर भी हम पहले मामले में नियमित रूप से नियोक्ता विधि की कॉल करेंगे और दूसरे मामले में विशेष कर्मचारी विधि की कॉल करेंगे

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

बस आउटपुट कंसोल देखें:

0.02
0.03

;)


आम तौर पर यह स्थिर तरीकों के 'ओवरराइडिंग' की अनुमति देने के लिए समझ में नहीं आता है क्योंकि रनटाइम पर कॉल करने के लिए कोई भी अच्छा तरीका नहीं होगा। कर्मचारी उदाहरण लेना, अगर हम RegularEmployee.getBonusMultiplier () को कॉल करते हैं - कौन सी विधि को निष्पादित किया जाना चाहिए?

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


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

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


खैर ... अगर आप जावा में ओवरड्रीन विधि का व्यवहार कैसे करते हैं, इस परिप्रेक्ष्य से आपको लगता है कि उत्तर नहीं है। लेकिन, यदि आप स्थिर विधि को ओवरराइड करने का प्रयास करते हैं तो आपको कोई कंपाइलर त्रुटि नहीं मिलती है। इसका मतलब है, अगर आप ओवरराइड करने का प्रयास करते हैं, तो जावा आपको ऐसा करने से नहीं रोकता है; लेकिन आपको निश्चित रूप से वही प्रभाव नहीं मिलता है जब आप गैर स्थैतिक तरीकों के लिए प्राप्त करते हैं। जावा में ओवरराइडिंग का मतलब है कि विशेष विधि ऑब्जेक्ट के रन टाइम प्रकार के आधार पर बुलाया जाएगा, न कि संकलित समय के प्रकार पर (जो ओवर्रिडेन स्थिर तरीकों के मामले में है)। ठीक है ... कारण के लिए कोई अनुमान है कि वे अजीब तरीके से क्यों व्यवहार करते हैं? चूंकि वे कक्षा के तरीके हैं और इसलिए उन तक पहुंच हमेशा संकलन समय के दौरान संकलित समय के दौरान संकलित समय के दौरान हल होती है। ऑब्जेक्ट संदर्भों का उपयोग करके उन्हें एक्सेस करना जावा के डिजाइनरों द्वारा दी गई एक अतिरिक्त स्वतंत्रता है और हमें निश्चित रूप से उस अभ्यास को रोकने के बारे में नहीं सोचना चाहिए जब वे इसे प्रतिबंधित करते हैं :-)

उदाहरण : आइए देखें कि क्या होता है यदि हम एक स्थिर विधि को ओवरराइड करने का प्रयास करते हैं: -

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

आउटपुट : -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

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


विधि ओवरराइडिंग गतिशील प्रेषण द्वारा संभव बनाया गया है, जिसका अर्थ है कि किसी वस्तु का घोषित प्रकार अपने व्यवहार को निर्धारित नहीं करता है, बल्कि इसके रनटाइम प्रकार:

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"

भले ही दोनों lassie और kermit को Animal प्रकार की वस्तुओं के रूप में घोषित किया गया हो, फिर भी उनका व्यवहार (विधि। .speak() ) भिन्न होता है क्योंकि गतिशील प्रेषण केवल विधि कॉल को bind करेगा। .speak() रन टाइम पर कार्यान्वयन के लिए - संकलन समय पर नहीं।

अब, यहां पर static कीवर्ड समझने लगता है: "स्थिर" शब्द "गतिशील" के लिए एक एंटोनिम है। इसलिए आप स्थिर तरीकों को ओवरराइड नहीं कर सकते हैं क्योंकि स्थिर सदस्यों पर कोई गतिशील प्रेषण नहीं है - क्योंकि स्थिर शब्द का अर्थ है "गतिशील नहीं"। यदि वे गतिशील रूप से प्रेषित होते हैं (और इस प्रकार अतिरंजित हो सकते हैं) static कीवर्ड अब और समझ में नहीं आता है।


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

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

यह कोड काम नहीं करेगा जैसा आप उम्मीद कर सकते हैं। अर्थात्, नियमित कर्मचारियों को नियमित कर्मचारियों की तरह 2% बोनस मिलता है। लेकिन अगर आप "स्थिर" को हटाते हैं, तो विशेष कर्मचारी को 3% बोनस मिलता है।

(माना जाता है कि, यह उदाहरण वास्तविक कोडिंग में खराब कोडिंग शैली है, आप शायद बोनस गुणक को हार्ड-कोडेड के बजाय किसी डेटाबेस में होना चाहते हैं। लेकिन ऐसा इसलिए है क्योंकि मैं बहुत कुछ उदाहरण के साथ उदाहरण नहीं देना चाहता था बिंदु के लिए अप्रासंगिक कोड।)

यह मेरे लिए काफी व्यावहारिक लगता है कि आप GetBonusMultiplier स्थिर बनाना चाहते हैं। शायद आप प्रत्येक श्रेणी में किसी कर्मचारी के उदाहरण की आवश्यकता के बिना कर्मचारियों की सभी श्रेणियों के लिए बोनस गुणक प्रदर्शित करने में सक्षम होना चाहते हैं। ऐसे उदाहरण उदाहरणों की खोज करने का क्या मतलब होगा? क्या होगा यदि हम कर्मचारी की एक नई श्रेणी बना रहे हैं और अभी तक कोई कर्मचारी नहीं सौंपा गया है? यह काफी तार्किक रूप से एक स्थिर कार्य है।

लेकिन यह काम नहीं करता है।

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

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

या शायद कुछ अच्छा कारण है कि जावा इस तरह से व्यवहार क्यों करता है। क्या कोई इस व्यवहार के लिए एक लाभ बता सकता है, इस समस्या से कुछ समस्याएं आसान हो गई हैं? मेरा मतलब है, मुझे सिर्फ जावा भाषा के spec पर इंगित न करें और कहें "देखें, यह दस्तावेज है कि यह कैसे व्यवहार करता है"। मुझे पता है कि। लेकिन क्या कोई अच्छा कारण है कि इसे इस तरह से व्यवहार करना चाहिए? (स्पष्ट के अलावा "इसे सही बनाना बहुत कठिन था" ...)

अद्यतन करें

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

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


स्टेटिक विधियों को जेवीएम द्वारा ग्लोबल के रूप में माना जाता है, ऑब्जेक्ट इंस्टेंस के लिए बिल्कुल बाध्य नहीं हैं।

यह अवधारणात्मक रूप से संभव हो सकता है यदि आप कक्षा वस्तुओं (जैसे स्मॉलटॉक जैसी भाषाओं में) से स्थिर तरीकों को कॉल कर सकते हैं लेकिन जावा में यह मामला नहीं है।

संपादित करें

आप स्थैतिक विधि अधिभारित कर सकते हैं, यह ठीक है। लेकिन आप एक स्थिर विधि को ओवरराइड नहीं कर सकते हैं, क्योंकि कक्षा कोई प्रथम श्रेणी की वस्तु नहीं है। आप किसी ऑब्जेक्ट की कक्षा को रन-टाइम पर प्राप्त करने के लिए प्रतिबिंब का उपयोग कर सकते हैं, लेकिन आपको प्राप्त ऑब्जेक्ट क्लास पदानुक्रम के समानांतर नहीं है।

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

आप कक्षाओं पर प्रतिबिंबित कर सकते हैं, लेकिन यह वहां रुक जाता है। आप clazz1.staticMethod() का उपयोग करके एक स्थिर विधि का आह्वान नहीं करते हैं, लेकिन clazz1.staticMethod() का उपयोग कर। एक स्थैतिक विधि किसी ऑब्जेक्ट से बंधी नहीं है और इसलिए इस बारे में कोई धारणा नहीं है और न ही एक स्थिर विधि में super है। एक स्थिर विधि एक वैश्विक कार्य है; नतीजतन, बहुरूपता की कोई धारणा भी नहीं है और इसलिए, विधि ओवरराइडिंग का कोई मतलब नहीं है।

लेकिन यह संभव हो सकता है यदि MyClass रन-टाइम पर एक ऑब्जेक्ट था जिस पर आप एक विधि का आह्वान करते हैं, जैसे कि स्मॉलटाक (या शायद एक टिप्पणी के रूप में जेआरबीई, लेकिन मुझे जेआरबीई के बारे में कुछ भी पता नहीं है)।

अरे, एक ओर बात। आप किसी ऑब्जेक्ट obj1.staticMethod() माध्यम से एक स्थिर विधि का आह्वान कर सकते हैं लेकिन यह वास्तव में obj1.staticMethod() लिए सिंटैक्टिक चीनी है और इससे बचा जाना चाहिए। यह आमतौर पर आधुनिक आईडीई में एक चेतावनी उठाता है। मुझे नहीं पता कि उन्होंने कभी इस शॉर्टकट की अनुमति क्यों दी।


A Static method, variable, block or nested class belongs to the entire class rather than an object.

A Method in Java is used to expose the behaviour of an Object / Class. Here, as the method is static (ie, static method is used to represent the behaviour of a class only.) changing/ overriding the behaviour of entire class will violate the phenomenon of one of the fundamental pillar of Object oriented programming ie, high cohesion . (remember a constructor is a special kind of method in Java.)

High Cohesion - One class should have only one role. For example: A car class should produce only car objects and not bike, trucks, planes etc. But the Car class may have some features(behaviour) that belongs to itself only.

Therefore, while designing the java programming language. The language designers thought to allow developers to keep some behaviours of a class to itself only by making a method static in nature.

The below piece code tries to override the static method, but will not encounter any compilation error.

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

This is because, here we are not overriding a method but we are just re-declaring it. Java allows re-declaration of a method (static/non-static).

Removing the static keyword from getVehileNumber() method of Car class will result into compilation error, Since, we are trying to change the functionality of static method which belongs to Vehicle class only.

Also, If the getVehileNumber() is declared as final then the code will not compile, Since the final keyword restricts the programmer from re-declaring the method.

public static final int getVehileNumber() {
return VIN;     }

Overall, this is upto software designers for where to use the static methods. I personally prefer to use static methods to perform some actions without creating any instance of a class. Secondly, to hide the behaviour of a class from outside world.


By overriding we can create a polymorphic nature depending on the object type. Static method has no relation with object. So java can not support static method overriding.


By overriding, you achieve dynamic polymorhpism. When you say overridng static methods, the words you are trying to use are contradictory.

Static says - compile time, overriding is used for dynamic polymorphism. Both are opposite in nature, and hence can't be used together.

Dynamic polymorhpic behavior comes when programmer uses an object and accessing an instance method. JRE will map different instance methods of different classes based on what kind of object you are using.

When you say overriding static methods, static methods we will access by using class name, which will be linked at compile time, so there is no concept of linking methods at run time with static methods. So the term "overriding" static methods itself doesn't make any meaning.

Note: even if you access a class method with an object, still java compiler is intelligent enough to find it out, and will do static linking.


Here is a simple explanation.A static method is associated with a class while an instance method is associated with a particular object.Overrides allow to call different implementation of the overridden methods associated with the particular object. So it is counter-intuitive to override static method which is not even associated with objects but class itself in the first place.So static methods cannot be overridden based on what object is calling it, it will always be associated with the class where it was created.


I like and double Jay's comment ( https://.com/a/2223803/1517187 ).
I agree that this is bad design of Java.
Many other languages support overriding static methods, as we see in previous comments. I feel Jay has also come to Java from Delphi like me.
Delphi (Object Pascal) was the first language implementing OOP.
It is obvious that many people had experience with that language, since it was in the past the only language to write commercial GUI products. And - yes, we could in Delphi override static methods. Actually, static methods in Delphi are called "class methods", while Delphi had different concept of "Delphi static methods" which were methods with early binding. To override methods you had to use late binding, declare "virtual" directive. So it was very convenient and intuitive and I would expect this in Java.


Overriding in Java simply means that the particular method would be called based on the run time type of the object and not on the compile time type of it (which is the case with overriden static methods). As static methods are class methods they are notinstance methods so they have nothing to do with the fact which reference is pointing to which Object or instance.as per the nature of static method it belongs to specific class, but you can redeclare it in to the subclass but that subclass doesn't know anything about the parent class' static methods because as I said it is specific to only that class in which it has been declared .Accessing them using object references is just an extra liberty given by the designers of Java and we should certainly not think of stopping that practice only when they restrict it more details and example http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html


The following code shows that it is possible:

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

} 

Yes..Practically Java's Allows to override static method...And No Theoretically......If you Override a static method in Java then it will compile and run smoothly..but it will lose Polymorphism....which is basic property of Java ..You will Read Everywhere that its not possible try yourself compling and running..you will get your answer...eg.If you Have Class Animal and a static method eat() and you Override that static method in its Subclass lets called it Dog..then when wherever you Assign a Dog object to an Animal Reference and call eat()..according to Java Dog's eat() should have been called..but in static Overriding Animals's eat() will Called..

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

According to Polymorphism Principle of Java the Output Should be Dog Eating .
But the result was different because to support Polymorphism Java uses Late Binding that means methods are called only at the run-time but not in the case of static methods..In static methods compiler calls methods at the compile time rather than the run-time..so we get methods according to the reference and not according to the object a reference a containing..that's why You can say Practically it supports static overring but theoretically it doesn't...





static-methods