मैं इंटरफ़ेस में स्थिर तरीकों की घोषणा क्यों नहीं कर सकता?


150

यह विषय सबसे कहता है - इस तथ्य का क्या कारण है कि एक इंटरफ़ेस में स्थिर तरीकों को घोषित नहीं किया जा सकता है?

public interface ITest {
    public static String test();
}

उपरोक्त कोड मुझे निम्न त्रुटि देता है (ग्रहण में, कम से कम): "इंटरफ़ेस विधि ITest.test () के लिए अवैध संशोधक; केवल सार्वजनिक और सार की अनुमति है"।


2
कृपया एस्पो के उत्तर को अस्वीकार कर दें, क्योंकि यह त्रुटिपूर्ण है। एक इंटरफ़ेस में एक क्लास-फाइल है जिसमें एक स्थैतिक विधि का कार्यान्वयन शामिल हो सकता है (यदि जावा-डिज़ाइनर इसकी अनुमति देगा), इसलिए स्थैतिक विधि के कार्यान्वयन को हल करने में कोई समस्या नहीं है। यह अन्य स्थिर वर्गों के साथ ठीक वैसा ही काम करता है।
ममेन्थ


9
यह Java 8 btw में उपलब्ध होगा।
m0skit0

1
@Vadorequest GIYF लेकिन वैसे भी, यहाँ देखें
m0skit0

जवाबों:


85

यहाँ खेलने में कुछ मुद्दे हैं। पहला एक स्थिर पद्धति को परिभाषित किए बिना घोषित करने का मुद्दा है। यही अंतर है

public interface Foo {
  public static int bar();
}

तथा

public interface Foo {
  public static int bar() {
    ...
  }
}

पहले उन कारणों के लिए असंभव है जो एस्पो का उल्लेख करता है: आपको नहीं पता कि कौन सा कार्यान्वयन वर्ग सही परिभाषा है।

जावा बाद की अनुमति दे सकता है ; और वास्तव में, जावा 8 में शुरू, यह करता है!


2
हाँ - यह तकनीकी नहीं है। कारण मैं इसे पसंद करूंगा। उस इंटरफ़ेस में एक स्थिर "कार्यान्वयन" विधि हो सकती है जो केवल इंटरफ़ेस में अन्य "इंटरफ़ेस" विधियों का संदर्भ देती है जिसे आसानी से कक्षाओं को लागू करके आसानी से उपयोग किया जा सकता है। लेकिन कोई एक इंटरफ़ेस में एक स्थिर वर्ग की घोषणा कर सकता है, इसलिए कोई भी ऐसी चीजें वहां रह सकता है जैसे MyInterface.Impl.doIt (MyInterface i, Object [] args) {...}
peterk

9
जावा 8 के बाद से, आप ए में staticतरीकों को परिभाषित कर सकते हैं interface। विधियाँ अवश्य होनी चाहिए public
ओलिवियर ग्रेजायर

4
@ ओलिवियरग्रेयर ... और उन्हें विरासत में नहीं मिला है, जो कि महत्वपूर्ण है।
विलियम एफ। जेम्सन

1
अच्छा जवाब है, हालांकि "लगभग बराबर" ROFLMAO xD मैं इसे "कुछ सदृश" जैसा लगता था।
तिमो

44

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


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

जावा में प्रत्येक इंटरफ़ेस प्रकार यह अपनी फ़ाइल के भीतर नहीं है, और न ही यह JLS के अनुसार होना चाहिए। इसके अतिरिक्त जेएलएस यह निर्धारित नहीं करता है कि कक्षाओं को हमेशा फ़ाइल सिस्टम के साथ संग्रहीत किया जाना चाहिए, इसके विपरीत।
व्लादिमीर

4
@Totophil: इंटरफेस एक जावा-फाइल में नहीं होना चाहिए, लेकिन इसमें कंपाइलिंग के बाद खुद की क्लास-फाइल होगी। यही मैंने लिखा है।
Mnementh

18

मैं एक उदाहरण के साथ आपके प्रश्न का उत्तर दूंगा। मान लीजिए कि हमारे पास एक मैथ क्लास है जिसमें स्टैटिक मेथड ऐड है। आप इस विधि को इस तरह कहेंगे:

Math.add(2, 3);

यदि गणित एक वर्ग के बजाय एक इंटरफ़ेस होता, तो इसमें कोई परिभाषित कार्य नहीं हो सकते थे। जैसे, Math.add (2, 3) जैसा कुछ कहना कोई मायने नहीं रखता।


11

कारण डिजाइन-सिद्धांत में निहित है, कि जावा कई उत्तराधिकार की अनुमति नहीं देता है। एकाधिक वंशानुक्रम की समस्या को निम्न उदाहरण द्वारा स्पष्ट किया जा सकता है:

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

अब अगर आप Cx () कहते हैं तो क्या होगा? एक्सिस () या बीएक्स () निष्पादित किया जाएगा? एकाधिक विरासत वाली प्रत्येक भाषा को इस समस्या को हल करना होगा।

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

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

यहाँ एक ही समस्या, अगर आप Cx () कहते हैं तो क्या होगा?


पतन का कोई कारण? एक व्याख्यात्मक टिप्पणी अच्छी होगी।
मेंमनेह

मैं नीच नहीं हूं, लेकिन क्या यह गैर-स्थिर तरीकों के लिए भी मान्य नहीं है?
नवाफल

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

ठीक है, कार्यान्वयन भाग को भूल जाओ। सवाल यह है कि हम घोषणा क्यों नहीं कर सकते। हाँ संकलक शिकायत करेगा और यह सवाल क्यों है। जिसके बारे में मुझे नहीं लगता कि आपने उत्तर दिया है।
नवाफल

1
कैसे स्थिति वहाँ इंटरफ़ेस की तुलना में किसी भी बदतर होगी Aहोते हैं int x(int z);और इंटरफ़ेस Bहोते हैं string x(int x);? x(3)इंटरफ़ेस C का अर्थ क्या है ?
सुपरकैट

7

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


5

अब Java8 हमें इंटरफ़ेस में भी स्टैटिक मेथड्स को परिभाषित करने की अनुमति देता है।

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

नोट: यदि हम स्पष्ट रूप से कीवर्ड्स का उपयोग नहीं करते हैं, तो डिफ़ॉल्ट रूप से कीवर्ड्स / स्टैटिक विधियों का सम्मान करते हैं।


4

यहां आपके प्रश्न का बहुत अच्छा और संक्षिप्त उत्तर है । (इसने मुझे यह समझाने का इतना सीधा-साधा तरीका समझा कि मैं इसे यहाँ से जोड़ना चाहता हूँ।)


यह सवाल का जवाब नहीं है, कम से कम यह एक टिप्पणी होनी चाहिए।
क्यूबजॉकी

3

ऐसा लगता है कि इंटरफ़ेस में स्थिर विधि जावा 8 में समर्थित हो सकती है , ठीक है, मेरा समाधान सिर्फ उन्हें आंतरिक वर्ग में परिभाषित करता है।

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

एक ही तकनीक का उपयोग एनोटेशन में भी किया जा सकता है:

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

आंतरिक वर्ग को हमेशा के Interface.fn...बजाय के रूप में एक्सेस किया जाना चाहिए Class.fn..., फिर, आप अस्पष्ट समस्या से छुटकारा पा सकते हैं।


2

एक इंटरफ़ेस का उपयोग बहुरूपता के लिए किया जाता है, जो वस्तुओं पर लागू होता है, न कि प्रकारों पर। इसलिए (जैसा कि पहले ही उल्लेख किया गया है) यह एक स्थिर इंटरफ़ेस सदस्य होने का कोई मतलब नहीं है।


कुछ चिंतनशील संदर्भों में लगभग समझ में आता है, हालांकि
Cruncher

1

जावा 8 ने दुनिया को बदल दिया था आपके पास इंटरफ़ेस में स्थिर तरीके हो सकते हैं लेकिन यह आपको इसके लिए कार्यान्वयन प्रदान करने के लिए मजबूर करता है।

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}


0

संशोधक का अवैध संयोजन: स्थिर और सार

यदि किसी वर्ग के सदस्य को स्थैतिक घोषित किया जाता है, तो इसका उपयोग उसके वर्ग के नाम के साथ किया जा सकता है, जो उस वर्ग तक सीमित रहता है, बिना वस्तु बनाए।

यदि किसी वर्ग के सदस्य को सार के रूप में घोषित किया जाता है, तो आपको कक्षा को सार घोषित करने की आवश्यकता होती है और आपको अपने मूल वर्ग (उप-वर्ग) में सार सदस्य के कार्यान्वयन की आवश्यकता होती है।

आपको उप-वर्ग में एक वर्ग के सार सदस्य को एक कार्यान्वयन प्रदान करने की आवश्यकता है जहां आप स्थैतिक विधि के व्यवहार को बदलने जा रहे हैं, जिसे सार के रूप में भी घोषित किया गया है जो आधार वर्ग तक सीमित है, जो सही नहीं है


यह प्रश्न का उत्तर कैसे देता है? क्लास के बारे में लिखते समय ओपी ने इंटरफ़ेस के बारे में पूछा।
भाग्यशाली

0

चूंकि स्थैतिक विधियां विरासत में नहीं मिल सकती हैं। तो कोई इंटरफ़ेस में रखने का उपयोग करें। इंटरफ़ेस मूल रूप से एक अनुबंध है जिसका उसके सभी ग्राहकों को पालन करना है। इंटरफ़ेस में एक स्थिर विधि रखने से ग्राहकों को इसे लागू करने के लिए मजबूर होना पड़ेगा। जो अब इस तथ्य के विरोधाभासी हो गया है कि स्थिर तरीके विरासत में नहीं मिल सकते हैं।


स्थैतिक तरीके हमेशा विरासत में मिलते हैं लेकिन उन्हें ओवरराइड नहीं किया जा सकता।
अक्की

0

जावा 8 के साथ , इंटरफेस में अब स्थिर तरीके हो सकते हैं।

उदाहरण के लिए, तुलनित्र के पास एक स्थिर प्राकृतिकऑडर () विधि है।

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


हे भगवान! हमारे पास एक गंभीर प्रोग्रामर है (और मैं, टिप्पणीकार) उत्तर देना (और मुझे, टिप्पणी करना) 10 साल पुराना सवाल।
मोहम्मद अनीस

मैंने तारीख पर ध्यान नहीं दिया :)
इशारा 3

Haha! कोई दिक्कत नहीं है!
मोहम्मद अनीस

-2

शायद एक कोड उदाहरण मदद करेगा, मैं C # का उपयोग करने जा रहा हूं, लेकिन आपको साथ चलने में सक्षम होना चाहिए।

आइए दिखाते हैं कि हमारे पास एक इंटरफ़ेस है जिसे IPayable कहा जाता है

public interface IPayable
{
    public Pay(double amount);
}

अब, हमारे पास दो ठोस वर्ग हैं जो इस इंटरफ़ेस को लागू करते हैं:

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

अब, दिखावा करते हैं कि हमारे पास विभिन्न खातों का एक संग्रह है, ऐसा करने के लिए हम IPayable प्रकार की एक सामान्य सूची का उपयोग करेंगे

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

अब, हम उन सभी खातों में $ 50.00 का भुगतान करना चाहते हैं:

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

तो अब आप देखते हैं कि कैसे इंटरफेस अविश्वसनीय रूप से उपयोगी हैं।

उनका उपयोग केवल तात्कालिक वस्तुओं पर किया जाता है। स्थिर वर्गों पर नहीं।

यदि आपने भुगतान स्थिर कर दिया है, तो जब IPayable के खातों के माध्यम से लूपिंग की जाती है, तो यह पता लगाने का कोई तरीका नहीं होगा कि उसे BusinessAcount या CustomerAccount पर भुगतान करना चाहिए या नहीं।


सिर्फ इसलिए कि स्थैतिक तरीके इस उदाहरण में कोई मतलब नहीं रखते हैं, इसका मतलब यह नहीं है कि वे किसी भी उदाहरण में समझ में नहीं आते हैं। आपके उदाहरण में अगर IPayable इंटरफ़ेस में स्थिर विधि "IncrementPayables" थी जो कि कितने पेबल्स जोड़े गए थे, तो यह एक वास्तविक उपयोग का मामला होगा। बेशक, कोई हमेशा एक अमूर्त वर्ग का उपयोग कर सकता है, लेकिन यह वह नहीं है जो आपने संबोधित किया है। अपने आप में आपका उदाहरण इंटरफेस में स्थिर तरीकों को कम नहीं करता है।
क्रंचर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.