जावा में स्थैतिक तरीके अमूर्त क्यों नहीं हो सकते?


592

सवाल जावा में है कि मैं एक अमूर्त स्टेटिक विधि को परिभाषित क्यों नहीं कर सकता? उदाहरण के लिए

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}

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

6
इस प्रश्न का उत्तर के लिए कुछ है, तो एक के रूप में पोस्ट जवाब , नहीं एक टिप्पणी
सोलोमन Ucko

जवाबों:


569

क्योंकि "अमूर्त" का अर्थ होता है: "इम्प्लीमेंट्स नो फंक्शनलिटी", और "स्टैटिस्टिकल" का अर्थ है: "यदि आपके पास वस्तु उदाहरण नहीं है तो भी कार्यक्षमता है"। और यह एक तार्किक विरोधाभास है।


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

12
@ टोमलाक मैं माफी मांगता हूं, मैं स्पष्ट नहीं था। बेशक एक स्थिर पद्धति 'वर्ग की है।' फिर भी, यह केवल इस अर्थ में है कि यह एक ही नामस्थान में रहता है। एक स्थिर विधि स्वयं क्लास ऑब्जेक्ट का एक तरीका नहीं है: यह 'ऑब्जेक्ट' को क्लास ऑब्जेक्ट के रूप में संचालित नहीं करता है, और यह विरासत की श्रृंखला में ठीक से भाग नहीं लेता है। यदि यह सही मायने में एक वर्ग विधि abstract staticहोती तो सही अर्थ होता। यह स्वयं क्लास ऑब्जेक्ट का एक तरीका होगा जो सबक्लास ऑब्जेक्ट्स को लागू करना होगा। बेशक, भाषा के बारे में मेरी पकड़ के बावजूद चीजें जिस तरह से आपका जवाब देती हैं, वह सही है।
अलेक्जेंडर लजबर्गबर्ग

693
यह एक तार्किक विरोधाभास नहीं है, यह एक भाषा की कमी है, कई अन्य भाषाएँ इस धारणा का समर्थन करती हैं। "अमूर्त" का अर्थ "उपवर्गों में लागू किया गया", "स्थिर" का अर्थ है "वर्ग उदाहरणों के बजाय वर्ग पर निष्पादित" कोई तार्किक विरोधाभास नहीं है।
एरिक ग्रेंज

10
@ एरिक: और फिर भी , आप जो कहते हैं वह लागू नहीं होता है abstract static: एक फ़ंक्शन एक्स जो "उपवर्ग में लागू किया गया है" एक ही समय में "कक्षा पर निष्पादित" नहीं हो सकता है - केवल उपवर्ग पर । जहां यह तब अमूर्त नहीं है।
तोमलक

72
@Tomakak: आपका तर्क परिपत्र है। static"खाली नहीं" का मतलब यह नहीं है - यह जावा के सिर्फ एक परिणाम है जो स्थिर तरीकों को अमूर्त नहीं होने देता है। इसका मतलब है "क्लास पर कॉल करने योग्य।" (इसका मतलब " क्लास पर केवल कॉल करने योग्य " होना चाहिए, लेकिन यह एक और मुद्दा है।) यदि जावा समर्थित abstract staticविधियां हैं, तो मुझे यह उम्मीद होगी कि विधि 1) उपवर्गों द्वारा लागू की जानी चाहिए, और 2) उपवर्ग का एक वर्ग तरीका है। कुछ तरीके सिर्फ उदाहरण के तरीकों के रूप में समझ में नहीं आते हैं। दुर्भाग्य से जावा आपको निर्दिष्ट नहीं करता है कि अमूर्त आधार वर्ग (या इंटरफ़ेस) बनाते समय।
माइकल कारमैन

326

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


25
जावा अजीब सीमाओं से भरा है। केवल अंतिम चर तक पहुंचने वाले क्लोजर एक और है। और शेष सूची लगभग अंतहीन है। उन्हें और उनके वर्कअराउंड को जानना जावा प्रोग्रामर का काम है। मस्ती करने के लिए हमें अपने खाली समय में जावा से बेहतर कुछ का उपयोग करना होगा। लेकिन मैं परेशान नहीं होता। यही प्रगति हासिल करने का बीज है।
छत

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

22
क्या "अमूर्त स्थैतिक" की अवधारणा OO सिद्धांतों का उल्लंघन है?
ट्रेवर

7
@threed, बिल्कुल नहीं, लेकिन निश्चित रूप से ऐसे लोग हैं जो कहते हैं कि staticस्वयं की अवधारणा पहले से ही एक उल्लंघन है ....
Pacerier

4
स्थैतिक की आवश्यकता एक स्पष्ट प्रदर्शन है कि "ओओ सिद्धांत" उतने व्यापक नहीं हैं जितना आमतौर पर दावा किया जाता है।
बेन

147

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


18
हाँ, यह वास्तव में शर्म की बात है कि जावा में स्थिर तरीकों को ओवरराइड नहीं किया जा सकता है।
मिशेल

12
@ मिचेल: क्या बात होगी? यदि आप उदाहरण आधारित व्यवहार चाहते हैं, तो उदाहरण विधियों का उपयोग करें।
रैन बिरनो

8
यह उत्तर गलत है। अमूर्त वर्गों में स्थैतिक तरीके ठीक काम करते हैं और आमतौर पर उपयोग किए जाते हैं। यह सिर्फ इतना है कि कक्षा के एक स्थिर तरीके ही अमूर्त नहीं हो सकते हैं। @ मिचेल यह एक स्थिर विधि को ओवरराइड करने का कोई मतलब नहीं है। एक उदाहरण के बिना, रनटाइम को कैसे पता चलेगा कि किस विधि को लागू करना है?
इरिकसन

63
@ हर्टसन - उदाहरण के बिना भी, वर्ग पदानुक्रम बरकरार है - स्थैतिक तरीकों पर विरासत उदाहरण के तरीकों की विरासत की तरह ही काम कर सकती है। स्मालटाक इसे करता है, और यह काफी उपयोगी है।
जारेड

8
@matiasg यह कोई नई बात नहीं है। सार वर्गों को हमेशा स्थिर, गैर-सार तरीकों की अनुमति दी गई है ।
मैट बॉल

70

abstractएक पद्धति के लिए एनोटेशन इंगित करता है कि विधि एक उपवर्ग में ओवरराइड किया जाना चाहिए।

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

चूंकि एक उपवर्ग में स्थिर सदस्यों को ओवरराइड नहीं किया जा सकता है, इसलिए abstractएनोटेशन उन पर लागू नहीं किया जा सकता है।

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

ClassA.methodA();

तथा

methodA();

SmallTalk में, वर्ग नाम वैकल्पिक नहीं है, इसलिए वाक्यविन्यास है (ध्यान दें कि SmallTalk "विषय" और "क्रिया" को अलग करने के लिए उपयोग नहीं करता है, बल्कि इसके बजाय स्टेटमेड टर्मिनेटर के रूप में उपयोग करता है):

ClassA methodA.

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


1
"उप-वर्ग द्वारा एक स्थिर सदस्य को ओवरराइड नहीं किया जा सकता है" गलत है। यह संभव है, कम से कम जावा 6 में। यकीन नहीं है कि कब से ऐसा है।
स्टीवन डी ग्रोट

15
@Steven De Groote एक स्थिर सदस्य वास्तव में उपवर्गों द्वारा ओवरराइड नहीं किया जा सकता है। यदि एक उपवर्ग में सुपरक्लास में एक स्थिर विधि के रूप में एक ही हस्ताक्षर के साथ एक स्थिर विधि है, तो यह इसे ओवरराइड नहीं करता है, यह इसे छुपाता है। http://docs.oracle.com/javase/tutorial/java/IandI/override.html अंतर यह है कि बहुरूपता केवल ओवरराइड के लिए काम करता है, लेकिन छिपे हुए तरीकों के लिए नहीं।
जॉन

2
@ जॉन 29 स्पष्टीकरण के लिए धन्यवाद, लेकिन नामकरण अंतर के अलावा यह उपयोग में समान लगता है।
स्टीवन डी ग्रोटे

2
@Steven De Groote हाँ, यह उपयोग में समान है, लेकिन व्यवहार भिन्न है। यही कारण है कि कोई स्थैतिक अमूर्त विधियां नहीं हैं - यदि वे बहुरूपता का समर्थन नहीं करते हैं तो स्थिर अमूर्त विधियों का क्या मतलब है?
जॉन

3
@Steven De Groote: अंतर तब स्पष्ट हो जाता है जब आपके पास सुपरक्लॉस में उस पद्धति के लिए एक कॉल होता है। मान लीजिए कि Super.foo सुपर.बार कहता है। यदि एक उपवर्ग उप-वर्ग को लागू करता है, और फिर foo को कॉल करता है, तो foo अभी भी Super.bar को कॉल करेगा, उप-वर्ग को नहीं। इसलिए, आपके पास वास्तव में दो पूरी तरह से अलग और असंबंधित विधियां हैं जिन्हें "बार" कहा जाता है। यह किसी भी उपयोगी अर्थ में ओवरराइडिंग नहीं है।
डोरैडस

14

मैंने भी यही सवाल पूछा, यहाँ क्यों है

चूंकि सार वर्ग कहता है, यह कार्यान्वयन नहीं देगा और उपवर्ग को इसे देने की अनुमति देगा

इसलिए सबक्लास को सुपरक्लास के तरीकों को ओवरराइड करना पड़ा,

नियम नंबर 1 - एक स्थिर विधि को ओवरराइड नहीं किया जा सकता है

क्योंकि स्थैतिक सदस्य और विधियाँ समय के तत्व संकलित होते हैं, इसीलिए स्थैतिक विधियों के अतिभार (संकलित समय बहुरूपता) की अनुमति दी जाती है, बजाय इसके बाद (रंटाइम पोलिमोर्फिज्म)

इसलिए, वे सार नहीं हो सकते।

अमूर्त स्थिर जैसी कोई चीज नहीं है <--- जावा यूनिवर्स में अनुमति नहीं है


5
-1, यह सच नहीं है कि "जावा स्थैतिक विधि को ओवरराइड करने की अनुमति नहीं देता है क्योंकि स्थैतिक सदस्य और विधियाँ संकलन समय तत्व हैं"। स्टेटिक प्रकार-चेकिंग के साथ निश्चित रूप से संभव है abstract staticदेखने stackoverflow.com/questions/370962/... । जावा के स्थैतिक तरीकों की अनुमति नहीं देने का असली कारण यह है कि जावा स्थैतिक तरीकों को ओवरराइड नहीं होने देता है।
पचेरियर

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

@ कैपटमैन मैन ओवरलोडिंग को शाब्दिक रूप से "पैरामीट्रिक पोलिमोर्फ़िज्म" कहा जाता है क्योंकि, पैरामीटर के प्रकार के आधार पर, एक अलग विधि कहा जाता है जो कि बहुरूपता है।
डावोर

12

यह एक भयानक भाषा डिजाइन है और वास्तव में इसका कोई कारण नहीं है कि यह कैसे संभव हो सकता है।

वास्तव में, यहाँ कैसे इस पर एक कार्यान्वयन है सकते में किया जा जावा :

public class Main {

        public static void main(String[] args) {
                // This is done once in your application, usually at startup
                Request.setRequest(new RequestImplementationOther());

                Request.doSomething();
        }

        public static final class RequestImplementationDefault extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something AAAAAA");
                }
        }

        public static final class RequestImplementaionOther extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something BBBBBB");
                }
        }

        // Static methods in here can be overriden
        public static abstract class Request {

                abstract void doSomethingImpl();

                // Static method
                public static void doSomething() {
                        getRequest().doSomethingImpl();
                }

                private static Request request;
                private static Request getRequest() {
                        // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. 
                        if ( request == null ) {
                                return request = new RequestImplementationDefault();
                        }
                        return request;
                }
                public static Request setRequest(Request r){
                        return request = r;
                }

        }
}

================= पुरानी मिसाल नीचे ================= नीचे

GetRequest, और getRequestImpl के लिए देखें ... setInstance को कॉल करने से पहले कार्यान्वयन को बदलने के लिए कहा जा सकता है।

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Mo. Joseph
 * @date 16 mar 2012
 **/

public abstract class Core {


    // ---------------------------------------------------------------        
    private static Core singleton; 
    private static Core getInstance() {
        if ( singleton == null )
            setInstance( new Core.CoreDefaultImpl() );  // See bottom for CoreDefaultImpl

        return singleton;
    }    

    public static void setInstance(Core core) {
        Core.singleton = core;
    }
    // ---------------------------------------------------------------        



    // Static public method
    public static HttpServletRequest getRequest() {      
        return getInstance().getRequestImpl();
    }


    // A new implementation would override this one and call setInstance above with that implementation instance
    protected abstract HttpServletRequest getRequestImpl();




    // ============================ CLASSES =================================

    // ======================================================================
    // == Two example implementations, to alter getRequest() call behaviour 
    // == getInstance() have to be called in all static methods for this to work
    // == static method getRequest is altered through implementation of getRequestImpl
    // ======================================================================

    /** Static inner class CoreDefaultImpl */
    public static class CoreDefaultImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    }

     /** Static inner class CoreTestImpl : Alternative implementation */
    public static class CoreTestImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return new MockedRequest();
        }
    }       

}

अनुसरण के रूप में उपयोग किया जाता है:

static {
     Core.setSingleton(new Core.CoreDefaultImpl());

     // Or

     Core.setSingleton(new Core.CoreTestImpl());

     // Later in the application you might use

     Core.getRequest(); 

}

6
मुझे समझ में नहीं आया कि आपने abstract staticप्रश्न में पूछे गए तरीके का उदाहरण कहां दिया है और आपने बोल्ड कैन बी डन इन जावा में लिखा है । यह पूरी तरह से भ्रामक है।
ब्लिप

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

यह एक अमूर्त वर्ग को विस्तारित करने का एक उदाहरण है, फिर बच्चे में स्थिर तरीकों को डालना। यह JAVA में CAN BE BEONE का उदाहरण नहीं है, किसी भी तरह से।
स्कूबा स्टीव

2
@ScubaSteve सबसे पहले, आप अपने निष्कर्ष पर गलत हैं। दूसरा, यह उसी परिणाम को प्राप्त करता है। मतलब एक वर्ग का स्थैतिक उपयोग दूसरे कार्यान्वयन द्वारा बदला जा सकता है। यह कहने का कोई जवाब नहीं है कि मैंने स्टेटिक कीवर्ड को अमूर्त बना दिया है, लेकिन इस पैटर्न का उपयोग करके आप स्टैटिक विधियों का उपयोग कर सकते हैं और फिर भी उनका कार्यान्वयन बदल सकते हैं। यह केवल वैश्विक होने का नकारात्मक प्रभाव डालता है, लेकिन एक परीक्षण / ठेस / देव वातावरण के लिए यह हमारे लिए चाल करता है।
mmm

5
  • एक अमूर्त विधि को केवल इसलिए परिभाषित किया जाता है ताकि इसे उपवर्ग में ओवरराइड किया जा सके। हालांकि, स्थिर तरीकों को ओवरराइड नहीं किया जा सकता है। इसलिए, अमूर्त, स्थिर विधि के लिए यह एक संकलन-समय की त्रुटि है।

    अब अगला सवाल यह है कि स्थैतिक तरीकों को ओवरराइड क्यों नहीं किया जा सकता है ??

  • यह इसलिए है क्योंकि स्थैतिक विधियाँ किसी विशेष वर्ग की होती हैं न कि उसके उदाहरण की। यदि आप किसी स्थिर विधि को ओवरराइड करने का प्रयास करते हैं, तो आपको कोई संकलन या रनटाइम त्रुटि नहीं मिलेगी, लेकिन कंपाइलर सुपरक्लास की स्थिर विधि को छिपा देगा।


4

एक स्थिर विधि, परिभाषा के अनुसार, जानने की जरूरत नहीं है this। इस प्रकार, यह एक आभासी तरीका नहीं हो सकता है (जो कि गतिशील उप-वर्ग जानकारी के अनुसार अतिभारित है this); इसके बजाय, एक स्थिर विधि अधिभार केवल संकलन समय पर उपलब्ध जानकारी के आधार पर है (इसका मतलब है: एक बार जब आप सुपरक्लास की एक स्थिर विधि का उल्लेख करते हैं, तो आप इसे सुपरक्लास विधि कहते हैं, लेकिन कभी भी उप-वर्ग विधि नहीं)।

इसके अनुसार, अमूर्त स्थैतिक विधियां काफी बेकार होंगी क्योंकि आप कभी भी इसका संदर्भ कुछ परिभाषित निकाय द्वारा प्रतिस्थापित नहीं करेंगे।


4

मैं देखता हूं कि पहले से ही एक ईश्वर-ज़िलिन उत्तर हैं लेकिन मुझे कोई व्यावहारिक समाधान नहीं दिखता है। बेशक यह एक वास्तविक समस्या है और जावा में इस सिंटैक्स को बाहर करने का कोई अच्छा कारण नहीं है। चूंकि मूल प्रश्न में एक संदर्भ का अभाव है, जहाँ इसकी आवश्यकता हो सकती है, मैं एक संदर्भ और एक समाधान प्रदान करता हूं:

मान लीजिए कि आपके पास कक्षाओं का एक समूह है जो समान हैं। ये विधियाँ एक विशिष्ट विधि कहलाती हैं जो विशिष्ट है:

class C1 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C1
    }
}
class C2 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C2
    }
}

doWork()तरीकों C1और C2समान हैं। इनमें से बहुत सी खामियां हो सकती हैं: C3 C4आदि। यदि static abstractअनुमति दी गई थी, तो आप कुछ ऐसा करके डुप्लिकेट कोड को समाप्त कर देंगे:

abstract class C {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }

    static abstract void doMoreWork(int k);
}

class C1 extends C {
    private static void doMoreWork(int k) {
        // code for class C1
    }
}

class C2 extends C {
    private static void doMoreWork(int k) {
        // code for class C2
    }
}

लेकिन यह संकलित नहीं होगा क्योंकि static abstractसंयोजन की अनुमति नहीं है। हालाँकि, इसे static classनिर्माण के साथ दरकिनार किया जा सकता है , जिसकी अनुमति है:

abstract class C {
    void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    abstract void doMoreWork(int k);
}
class C1 {
    private static final C c = new  C(){  
        @Override void doMoreWork(int k) {
            System.out.println("code for C1");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}
class C2 {
    private static final C c = new C() {
        @Override void doMoreWork(int k) {
            System.out.println("code for C2");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}

इस समाधान के साथ केवल एक ही कोड डुप्लिकेट है

    public static void doWork() {
        c.doWork();
    }

1
चूँकि आपके अंतिम समाधान में एब्स्ट्रैक्ट क्लास सी में कोई स्टैटिक विधियाँ नहीं हैं, तो क्यों न केवल C1 और C2 को इसे विस्तारित किया जाए और doMoreWork () विधि को ओवरराइड किया जाए और किसी भी अन्य वर्ग को इसका उदाहरण बनाने और आवश्यक विधियों को कॉल करने की अनुमति दी जाए। मूल रूप से आप अनाम कक्षा का उपयोग करके और फिर C1 और C2 में एक ही अर्थात फैली हुई कक्षा C का उपयोग कर रहे हैं और अपने स्थिर उदाहरण का उपयोग करते हुए एक स्थिर विधि के भीतर से प्रवेश कर सकते हैं लेकिन इसकी आवश्यकता बिल्कुल नहीं है।
sactiw

मैं आपके द्वारा प्रदान किए गए संदर्भ को नहीं समझता। अपने अंतिम समाधान में आप क्या कर सकते हैं कॉल C1.doWork()या C2.doWork()लेकिन आप कॉल नहीं कर सकते C.doWork()। इसके अलावा, आपके द्वारा प्रदान किए गए उदाहरण में, जो काम नहीं करेगा, मान लीजिए कि अगर इसकी अनुमति दी गई है, तो क्लास किस तरह Cसे कार्यान्वयन का पता लगाएगा doMoreWork()? अंत में मैं आपके संदर्भ कोड को एक खराब डिज़ाइन कहूंगा। क्यों? केवल इसलिए कि आपने कोड के लिए एक अलग फ़ंक्शन बनाया है जो उस कोड के लिए फ़ंक्शन बनाने के बजाय जो सामान्य है और फिर कक्षा में एक स्थिर फ़ंक्शन को लागू कर रहा है C। यह आसान है !!!
Blip

2

मान लें कि दो वर्ग हैं, Parentऔर ChildParentहै abstract। घोषणाएं इस प्रकार हैं:

abstract class Parent {
    abstract void run();
}

class Child extends Parent {
    void run() {}
}

इसका मतलब यह है कि किसी भी उदाहरण Parentको निर्दिष्ट करना चाहिए कि कैसे run()निष्पादित किया जाता है।

हालाँकि, अब मान लें कि Parentयह नहीं है abstract

class Parent {
    static void run() {}
}

इसका मतलब है कि Parent.run()स्थैतिक विधि को निष्पादित करेगा।

एक abstractविधि की परिभाषा "एक विधि है जिसे घोषित किया गया है लेकिन लागू नहीं किया गया है", जिसका अर्थ है कि यह स्वयं कुछ भी वापस नहीं करता है।

एक staticविधि की परिभाषा "एक विधि है जो समान मापदंडों के लिए उसी मान को लौटाती है, जिस पर इसे कहा जाता है"।

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

इसके अलावा, एक static abstractविधि के लिए वास्तव में बहुत अधिक कारण नहीं है ।


2

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


1
सार कक्षाएं निश्चित रूप से स्थिर तरीके हो सकती हैं। लेकिन स्थिर सार विधियां नहीं।
जैकसनऑफ

2

एक विधि के रूप की घोषणा staticका मतलब है हम अपने वर्ग के नाम से उस विधि कॉल कर सकते हैं और यदि उस वर्ग है abstractऔर साथ ही, यह कोई मतलब नहीं है इसे कहते हैं के रूप में यह शरीर के किसी भी शामिल नहीं है, और इसलिए हम दोनों के रूप में एक प्रणाली की घोषणा नहीं कर सकते हैं staticऔर abstract


2

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


1

एक स्थिर विधि को कक्षा के उदाहरण के बिना कहा जा सकता है। अपने उदाहरण में आप foo.bar2 () कह सकते हैं, लेकिन foo.bar () नहीं, क्योंकि बार के लिए आपको एक उदाहरण की आवश्यकता होती है। निम्नलिखित कोड काम करेगा:

foo var = new ImplementsFoo();
var.bar();

यदि आप एक स्थिर विधि कहते हैं, तो इसे हमेशा एक ही कोड निष्पादित किया जाएगा। उपरोक्त उदाहरण में, भले ही आप ImplementsFoo में बार 2 को फिर से परिभाषित करें, var.bar2 () पर कॉल foo.bar2 () निष्पादित करेगा।

यदि बार 2 में अब कोई कार्यान्वयन नहीं है (जो कि सार का मतलब है), तो आप कार्यान्वयन के बिना एक विधि कह सकते हैं। यह बहुत हानिकारक है।


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

3
वास्तव में, मैं गलत था। आप एक इंटरफ़ेस में स्थिर तरीके नहीं रख सकते। भाषा का दोष।
फिजियारोन

1

मेरा मानना ​​है कि मुझे इस सवाल का जवाब मिल गया है, क्यों एक इंटरफ़ेस के तरीके (जो एक मूल वर्ग में अमूर्त तरीकों की तरह काम करते हैं) स्थिर नहीं हो सकते। यहाँ पूरा जवाब है (मेरा नहीं)

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

यदि आप एक स्थिर पद्धति को कॉल कर रहे हैं, तो आप पहले से ही उस वर्ग को जानते हैं जहां यह लागू किया गया है, या इसका कोई प्रत्यक्ष उपवर्ग। यदि आप परिभाषित करते हैं

abstract class Foo {
    abstract static void bar();
}

class Foo2 {
    @Override
    static void bar() {}
}

फिर कोई भी Foo.bar();कॉल स्पष्ट रूप से अवैध है, और आप हमेशा उपयोग करेंगे Foo2.bar();

इसे ध्यान में रखते हुए, एक स्थिर अमूर्त पद्धति का एकमात्र उद्देश्य इस तरह की विधि को लागू करने के लिए उपवर्गों को लागू करना होगा। आप शुरू में सोच सकते हैं इस बहुत गलत है, लेकिन अगर आप एक सामान्य प्रकार पैरामीटर है <E extends MySuperClass>यह इंटरफ़ेस के माध्यम से है कि गारंटी करने के लिए अच्छा होगा Eकर सकते हैं .doSomething()। ध्यान रखें कि टाइप इरेज़र जेनरिक के कारण केवल संकलन के समय ही मौजूद होते हैं।

तो, क्या यह उपयोगी होगा? हां, और शायद यही वजह है कि जावा 8 इंटरफेस में स्थिर तरीकों की अनुमति दे रहा है (हालांकि केवल एक डिफ़ॉल्ट कार्यान्वयन के साथ)। कक्षाओं में डिफ़ॉल्ट कार्यान्वयन के साथ सार स्थिर तरीके क्यों नहीं? केवल इसलिए कि डिफ़ॉल्ट कार्यान्वयन के साथ एक अमूर्त विधि वास्तव में एक ठोस विधि है।

कोई डिफ़ॉल्ट कार्यान्वयन के साथ सार / इंटरफ़ेस स्थिर तरीके क्यों नहीं? जाहिरा तौर पर, केवल इसलिए कि जावा जिस तरह से पहचानता है कि उसे किस कोड को निष्पादित करना है (मेरे उत्तर का पहला भाग)।


1

क्योंकि अमूर्त वर्ग एक OOPS अवधारणा है और स्थैतिक सदस्य OOPS का हिस्सा नहीं हैं ....
अब बात यह है कि हम इंटरफ़ेस में स्थैतिक पूर्ण विधियों की घोषणा कर सकते हैं और हम इंटरफ़ेस के अंदर मुख्य विधि की घोषणा करके इंटरफ़ेस निष्पादित कर सकते हैं

interface Demo 
{
  public static void main(String [] args) {
     System.out.println("I am from interface");
  }
}

0

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

इस प्रकार, आप उदाहरण के लिए एक छांटने योग्य सार वर्ग या यहां तक ​​कि (ऑटो-) सार स्थैतिक विधियों के साथ इंटरफेस बना सकते हैं, जो क्रमबद्ध विकल्पों के मापदंडों को परिभाषित करता है:

public interface SortableObject {
    public [abstract] static String [] getSortableTypes();
    public String getSortableValueByType(String type);
}

अब आप एक छांटने योग्य वस्तु को परिभाषित कर सकते हैं जिसे मुख्य प्रकारों द्वारा क्रमबद्ध किया जा सकता है जो इन सभी वस्तुओं के लिए समान हैं:

public class MyDataObject implements SortableObject {
    final static String [] SORT_TYPES = {
        "Name","Date of Birth"
    }
    static long newDataIndex = 0L ;

    String fullName ;
    String sortableDate ;
    long dataIndex = -1L ;
    public MyDataObject(String name, int year, int month, int day) {
        if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
        if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
        this.fullName = name ;
        this.sortableDate = MyUtils.createSortableDate(year,month,day);
        this.dataIndex = MyDataObject.newDataIndex++ ;
    }
    public String toString() {
        return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
    }

    // override SortableObject 
    public static String [] getSortableTypes() { return SORT_TYPES ; }
    public String getSortableValueByType(String type) {
        int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
        switch(index) {
             case 0: return this.name ;
             case 1: return this.sortableDate ;
        }
        return toString(); // in the order they were created when compared
    }
}

अब आप एक बना सकते हैं

public class SortableList<T extends SortableObject> 

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

String [] MenuItems = T.getSortableTypes();

एक उदाहरण का उपयोग करने के साथ समस्या यह है कि SortableList में अभी तक आइटम नहीं हो सकते हैं, लेकिन पहले से ही पसंदीदा सॉर्टिंग प्रदान करने की आवश्यकता है।

चेरियो, ओलाफ।


0

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

अब, जिस तरह से जावा स्टैटिक विधियों से संबंधित है , वह उस वर्ग के सभी उदाहरणों के साथ विधि साझा करने से है।

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

बूम।


अमूर्त वर्ग की प्रत्येक विधि को क्रियान्वित करने के लिए अपने वर्ग को वैसे भी विस्तारित करने की आवश्यकता होती है, इसलिए यह कोई बहाना नहीं है। आप अमूर्त वर्ग (एक ही समय में, अमूर्त विधि को लागू करने) का विस्तार कर सकते हैं। तो यह एक स्पष्टीकरण के रूप में काम नहीं करता है।
पेरे

0

जावा डॉक्टर के अनुसार :

एक स्थिर विधि एक विधि है जो उस वर्ग से जुड़ी होती है जिसमें इसे किसी वस्तु के बजाय परिभाषित किया जाता है। कक्षा का हर उदाहरण अपने स्थिर तरीकों को साझा करता है

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

इसका एक अच्छा उदाहरण है:

list.sort(ordering);

के बजाय

Collections.sort(list, ordering);

स्थैतिक तरीकों का उपयोग करने का एक और उदाहरण भी डॉक्टर में ही दिया गया है:

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

0

क्योंकि 'एब्सट्रैक्ट' का मतलब है कि विधि को ओवरराइड करना है और कोई 'स्टैटिक' तरीकों को ओवरराइड नहीं कर सकता।


यह उत्तर कुछ भी नहीं जोड़ता है कि पिछले उत्तरों को पहले से ही संबोधित नहीं किया गया है।
मार्सटॉमिक

@MarsAtomic मुझे लगता है कि यह अधिक उपयुक्त है तो शीर्ष मतदान जवाब। इसके अलावा, यह सफल है।
प्रवीण कुमार

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

मैं असहमत हूं, कृपया मेरे उत्तर की तुलना अन्य से करें, विशेष रूप से शीर्ष मतदान जवाब।
प्रवीण कुमार 7

"मैं ऐसा क्यों नहीं कर सकता?" उत्तर: "क्योंकि आप नहीं कर सकते हैं"।
जैक्सऑन एफ

0

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

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


0

क्योंकि अमूर्त एक ऐसा कीवर्ड है जो अमूर्त तरीकों पर लागू होता है जो एक निकाय को निर्दिष्ट नहीं करता है। और अगर हम स्थैतिक कीवर्ड के बारे में बात करते हैं तो यह वर्ग क्षेत्र से संबंधित है।


कृपया अपने उत्तर के बारे में थोड़ा विस्तार करें।
ब्लिप

0

क्योंकि यदि आप कक्षा में किसी स्थिर सदस्य या स्थिर चर का उपयोग कर रहे हैं तो यह कक्षा के लोडिंग समय पर लोड होगा।


3
और यह एक मुद्दा क्यों होगा?
ईस

-1

आप इसे जावा 8 में इंटरफेस के साथ कर सकते हैं।

यह इसके बारे में आधिकारिक दस्तावेज है:

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


2
कैसे? मैं समाधान के लिए देखा है और किसी भी नहीं मिल सकता है।
तूएलिआ

Wut? आप नहीं कर सकते। इंटरफ़ेस क्लास का उपयोग करके सभी स्थिर इंटरफ़ेस विधियों को लागू करना है।
mmm

8
यह उत्तर गलत है और जावा में नए लोगों को गुमराह कर रहा है। यह अमूर्त स्थिर विधि के किसी भी उदाहरण को दिखाने के लिए करता है क्योंकि इसे लागू नहीं किया जा सकता है और अन्य उत्तर में कहा गया है
Blip

-1

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


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