जावा C # एक्सटेंशन विधियों के बराबर है


176

मैं ऑब्जेक्ट की एक सूची में एक कार्यक्षमता को लागू करने के लिए देख रहा हूं जैसा कि मैं C # में एक एक्सटेंशन विधि का उपयोग कर रहा हूं।

कुछ इस तरह:

List<DataObject> list;
// ... List initialization.
list.getData(id);

मैं जावा में कैसे करूँ?


8
इसे एक जांचें: github.com/nicholas22/jpropel, उदाहरण: नया स्ट्रिंग [] {"जेम्स", "जॉन", "जॉन", "एडी"}। जगह (प्रारंभ ("जे")) विशिष्ट (); यह lombok-pg का उपयोग करता है जो विस्तार विधि अच्छाई प्रदान करता है।
NT_

6
जब उन्होंने एक्सटेंशन की अनुमति दी तो Microsoft निश्चित रूप से सही हो गया। नई कार्यक्षमता जोड़ने के लिए उपवर्ग काम नहीं करता है, अगर मुझे एक वर्ग में फ़ंक्शन की आवश्यकता होती है जो मुझे कहीं और लौटाता है। जैसे स्ट्रिंग और दिनांक में विधियाँ जोड़ना।
टेगनेन

3
यानी java.lang.String एक अंतिम वर्ग है, इसलिए आप इसे विस्तारित नहीं कर सकते। स्थैतिक तरीकों का उपयोग करना एक तरीका है, लेकिन यह कभी-कभी कोड को अपठनीय दिखाता है। मुझे लगता है कि सी # एक उम्र को कंप्यूटर लैंग के रूप में छोड़ देता है। विस्तार के तरीके, आंशिक कक्षाएं, LINQ और इतने पर ..
दावुत गार्बुज़

7
@ रोराडनर, रॉल्फ! एक लापता भाषा सुविधा के लिए सबसे अच्छा प्रतिशोध यह है कि लापता भाषा सुविधा बुराई और अवांछित है। यह ज्ञात है।
कर्क वॉक

6
एक्सटेंशन विधियां "बुराई" नहीं हैं। वे कोड पठनीयता में बहुत सुधार करते हैं। जावा में कई खराब डिजाइन निर्णयों में से केवल एक और।
csauve

जवाबों:


196

जावा एक्सटेंशन के तरीकों का समर्थन नहीं करता है।

इसके बजाय, आप एक नियमित स्थैतिक विधि बना सकते हैं, या अपनी कक्षा लिख ​​सकते हैं।


63
एक्सटेंशन विधियों का उपयोग करने के बाद इम खराब हो गया है - लेकिन स्थैतिक विधियां चाल भी करेगी।
bbqchickenrobot

31
लेकिन वाक्यविन्यास बहुत अच्छा है, और कार्यक्रम को समझने में आसान बनाता है :) मुझे यह भी पसंद है कि रूबी आपको लगभग एक ही काम करने की अनुमति देता है, सिवाय इसके कि आप वास्तव में निर्मित कक्षाओं को संशोधित कर सकते हैं और नए तरीके जोड़ सकते हैं।
ज्ञातव्य

18
@Ken: हाँ, और यह पूरी बात है! आप जावा में क्यों लिखते हैं और सीधे जेवीएम बाइट कोड में नहीं? क्या यह "सिंटैक्स की बात नहीं है"?
फ्योडोर सोइकिन

30
विस्तार विधियाँ कुछ अन्य वर्ग के अतिरिक्त स्थैतिक तरीकों की तुलना में कोड को अधिक सुरुचिपूर्ण बना सकती हैं। लगभग सभी अधिक आधुनिक भाषाएं किसी प्रकार के मौजूदा वर्ग विस्तार के लिए अनुमति देती हैं: C #, php, उद्देश्य-सी, जावास्क्रिप्ट। जावा निश्चित रूप से यहां अपनी उम्र दिखाता है। कल्पना कीजिए कि आप डिस्क पर JSONObject लिखना चाहते हैं। क्या आप jsonobj.writeToDisk () या someunrelatedclass.writeToDisk (jsonobj) कहते हैं?
woens

8
जावा से नफरत करने के कारण बढ़ते रहते हैं। और मैंने कुछ साल पहले उनकी तलाश बंद कर दी थी ......
जॉन डेमेट्रियौ

54

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

और मुझे नहीं लगता कि जावा के जेनेरिक मापदंडों के प्रकार के मिटाए जाने वाले शब्दार्थ के कारण उन्हें जावा में लागू करना संभव है।


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

25
यह पूरा उत्तर गलत है। C # में एक्सटेंशन मेथड सिंटैक्टिक शुगर है जिसे कंपाइलर स्टैटिक मेथड के पहले लॉजिक मे मेथड कॉल के टारगेट को मूव करने के लिए थोड़ा रीक्रिएट करता है। आप मौजूदा तरीकों को ओवरराइड नहीं कर सकते। कोई आवश्यकता नहीं है कि एक विस्तार विधि एक सन्यासी हो। इसका शाब्दिक रूप से एक स्थिर विधि को कॉल करने का एक अधिक सुविधाजनक तरीका है, जो एक वर्ग के लिए इंस्टेंस विधियों को जोड़ने का रूप देता है। कृपया इसे पढ़ें अगर आप इस जवाब से सहमत हैं
मैट क्लेन

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

1
@ user1686250 यह जावा में लागू करने के लिए संभव है ("जावा" द्वारा मुझे लगता है कि आप का मतलब है कि बायटेकोड है जो एक जेवीएम पर चलता है) ... कोटलिन, जो बायटेकोड के संकलन का विस्तार करता है। यह सिर्फ स्टैटिक मेथड के मुकाबले सिंटैक्टिक शुगर है। आप यह देखने के लिए IntelliJ में डिकंपाइलर का उपयोग कर सकते हैं कि समकक्ष जावा कैसा दिखता है।
जेफरी ब्लाटमैन

@ user1686250 क्या आप विकसित कर सकते हैं कि आप जेनरिक के बारे में क्या लिख ​​रहे हैं (या लिंक दें) क्योंकि मैं बिल्कुल जेनरिक के बारे में बात नहीं करता। सामान्य स्थैतिक विधियों के अलावा यह किस तरीके से संबंधित है?
सी। शेम्पेन

17

प्रोजेक्ट लोम्बोक एक एनोटेशन प्रदान करता है@ExtensionMethod है जिसका उपयोग उस कार्यक्षमता को प्राप्त करने के लिए किया जा सकता है जिसे आप पूछ रहे हैं।


3
मैनिफोल्ड जावा के लिए व्यापक, निर्बाध सी # -स्टाइल एक्सटेंशन विधि का समर्थन प्रदान करता है , जिससे आप उन कक्षाओं में विधियों को जोड़ सकते हैं, जिन्हें आप नियंत्रित नहीं करते हैं java.lang.String। प्रदर्शन: http://manifold.systems/images/ExtensionMethod.mp4
स्कॉट

10

तकनीकी रूप से C # एक्सटेंशन का जावा में कोई समकक्ष नहीं है। लेकिन अगर आप क्लीनर कोड और रखरखाव के लिए ऐसे कार्यों को लागू करना चाहते हैं, तो आपको मैनिफोल्ड ढांचे का उपयोग करना होगा।

package extensions.java.lang.String;

import manifold.ext.api.*;

@Extension
public class MyStringExtension {

  public static void print(@This String thiz) {
    System.out.println(thiz);
  }

  @Extension
  public static String lineSeparator() {
    return System.lineSeparator();
  }
}

7

Xtend भाषा - जो जावा के एक सुपर सेट है, और compiles जावा स्रोत कोड के लिए 1  - इस का समर्थन करता है।


जब वह कोड जो जावा नहीं है, तो उसे जावा में संकलित किया जाता है, तो क्या आपके पास एक्सटेंशन पद्धति है? या जावा कोड सिर्फ एक स्थिर विधि है?
फैबियो मिल्हीरो

@Bomboca जैसा कि अन्य ने उल्लेख किया है, जावा में विस्तार विधियाँ नहीं हैं। तो XTend कोड, जावा के लिए संकलित, किसी भी तरह से एक जावा एक्सटेंशन विधि नहीं बनाता है। लेकिन अगर आप एक्सटेंड में विशेष रूप से काम करते हैं तो आप नोटिस या देखभाल नहीं करेंगे। लेकिन, अपने प्रश्न का उत्तर देने के लिए, आपके पास जरूरी नहीं है कि एक स्थिर विधि हो। XTend के मुख्य लेखक के पास इस बारे में एक ब्लॉग प्रविष्टि है। blog.efftinge.de/2011/11/…
Erick G. Hagstrom

हां, मुझे नहीं पता कि मैंने ऐसा क्यों नहीं सोचा। धन्यवाद!
फेबियो मिल्हीरो

@ मुझे XTend से परिचित कराने के लिए धन्यवाद - मैंने इसके बारे में कभी नहीं सुना।
jpaugh

7

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

इसके अतिरिक्त, IntelliJ मैनिफोल्ड प्लगइन के माध्यम से कई गुना व्यापक समर्थन प्रदान करता है

मैनिफोल्ड एक ओपन सोर्स प्रोजेक्ट है जो गीथब पर उपलब्ध है ।



5

जावा में ऐसी सुविधा नहीं है। इसके बजाय आप अपनी सूची कार्यान्वयन के नियमित उपवर्ग बना सकते हैं या अनाम आंतरिक वर्ग बना सकते हैं:

List<String> list = new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
};

समस्या इस पद्धति को कॉल करने की है। आप इसे "जगह में" कर सकते हैं:

new ArrayList<String>() {
   public String getData() {
       return ""; // add your implementation here. 
   }
}.getData();

112
जो कि बिलकुल बेकार है।
SLaks

2
@ शेक्स: बिल्कुल क्यों? यह एक "अपनी खुद की लिखी कक्षा" है जो आपके द्वारा सुझाई गई है।
गोरान जोविक

23
@ गोरान: यह सब आपको करने की अनुमति देता है एक विधि को परिभाषित करें, फिर इसे तुरंत कॉल करें, एक बार
SLaks

3
@ स्लैक्स: बिलकुल ठीक, पॉइंट लिया गया। उस सीमित समाधान की तुलना में, नामांकित वर्ग लिखना बेहतर होगा।
गोरान जकोव

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

4

ऐसा लगता है कि कुछ छोटे मौके हैं जो डिफेंडर मेथड्स (यानी डिफॉल्ट मेथड्स) इसे जावा 8 में बना सकते हैं। हालांकि, जहां तक ​​मैं उन्हें समझता हूं, वे केवल एक के लेखकinterface को पीछे हटने की इजाजत देते हैं , न कि यूजर्स को।

डिफेंडर के तरीके + इंटरफ़ेस इंजेक्शन फिर सी # -स्टाइल एक्सटेंशन विधियों को पूरी तरह से लागू करने में सक्षम होगा, लेकिन AFAICS, इंटरफ़ेस इंजेक्शन अभी भी जावा 8 रोड-मैप पर नहीं है।


3

इस प्रश्न पर पार्टी के लिए देर से, लेकिन किसी को भी यह उपयोगी लगता है तो मैंने सिर्फ एक उपवर्ग बनाया:

public class ArrayList2<T> extends ArrayList<T> 
{
    private static final long serialVersionUID = 1L;

    public T getLast()
    {
        if (this.isEmpty())
        {
            return null;
        }
        else
        {       
            return this.get(this.size() - 1);
        }
    }
}

4
विस्तार विधियाँ आमतौर पर ऐसे कोड के लिए होती हैं जिन्हें अंतिम / मुहरबंद वर्गों की तरह संशोधित या विरासत में नहीं दिया जा सकता है और इसकी मुख्य शक्ति IEnumerable <T> के विस्तार वाले इंटरफेस की तरह है। बेशक, वे स्थैतिक तरीकों के लिए केवल वाक्यात्मक चीनी हैं। उद्देश्य यह है कि कोड अधिक पठनीय हो। क्लीनर कोड का अर्थ है बेहतर रखरखाव / विकास।
mbx

1
वह सिर्फ @mbx नहीं है। एक्सटेंशन विधियाँ गैर-सील की गई कक्षाओं की कक्षा की कार्यक्षमता को बढ़ाने के लिए भी उपयोगी होती हैं, लेकिन जिसे आप विस्तारित नहीं कर सकते हैं क्योंकि आप जो भी रिटर्न इंस्टेंसेस को नियंत्रित नहीं करते हैं, उदाहरण के लिए HttpContextBase जो एक अमूर्त वर्ग है।
फाबियो मिल्हीरो

@FabioMilheiro मैंने उदारतापूर्वक उस संदर्भ में "इंटरफेस" के रूप में अमूर्त वर्गों को शामिल किया। ऑटो जेनरेट की गई कक्षाएं (xsd.exe) एक ही तरह की होती हैं: आप जनरेट की गई फाइलों को संशोधित करके उन्हें बढ़ा नहीं सकते। आप सामान्य रूप से "आंशिक" का उपयोग करके उन्हें विस्तारित करेंगे जिसके लिए उन्हें उसी विधानसभा में निवास करना होगा। यदि वे नहीं हैं, तो विस्तार विधियाँ एक बहुत ही अच्छा विकल्प है। अंततः, वे केवल स्थैतिक तरीके हैं (यदि आप उत्पन्न IL कोड को देखते हैं तो कोई अंतर नहीं है)।
mbx

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

2

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

public interface Extension<T> {

    default T base() {
        return null;
    }
}

हम शून्य वापस आते हैं क्योंकि इंटरफेस में स्थिति नहीं हो सकती है, लेकिन इसे बाद में प्रॉक्सी के माध्यम से तय किया जाना चाहिए।

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

public interface ListExtension<T> extends Extension<List<T>> {

    default void foreach(Consumer<T> consumer) {
        for (T item : base()) {
            consumer.accept(item);
        }
    }

}

चूँकि हम एक्सटेंशन इंटरफ़ेस का विस्तार करते हैं, इसलिए हम अपने द्वारा अटैच किए गए समर्थन ऑब्जेक्ट तक पहुंचने के लिए बेस () विधि को अपनी एक्सटेंशन विधि के अंदर कॉल कर सकते हैं।

एक्सटेंशन इंटरफ़ेस में फ़ैक्टरी विधि होनी चाहिए जो किसी दिए गए समर्थन ऑब्जेक्ट का एक्सटेंशन बनाएगी:

public interface Extension<T> {

    ...

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }
}

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

public class ExtensionHandler<T> implements InvocationHandler {

    private T instance;

    private ExtensionHandler(T instance) {
        this.instance = instance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if ("base".equals(method.getName())
                && method.getParameterCount() == 0) {
            return instance;
        } else {
            Class<?> type = method.getDeclaringClass();
            MethodHandles.Lookup lookup = MethodHandles.lookup()
                .in(type);
            Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
            makeFieldModifiable(allowedModesField);
            allowedModesField.set(lookup, -1);
            return lookup
                .unreflectSpecial(method, type)
                .bindTo(proxy)
                .invokeWithArguments(args);
        }
    }

    private static void makeFieldModifiable(Field field) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField
                .setInt(field, field.getModifiers() & ~Modifier.FINAL);
    }

}

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

public class Program {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");
        ListExtension<String> listExtension = Extension.create(ListExtension.class, list);
        listExtension.foreach(System.out::println);
    }

}

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

नीचे आपको एक्सटेंशन इंटरफ़ेस का कोड मिल सकता है:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public interface Extension<T> {

    public class ExtensionHandler<T> implements InvocationHandler {

        private T instance;

        private ExtensionHandler(T instance) {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if ("base".equals(method.getName())
                    && method.getParameterCount() == 0) {
                return instance;
            } else {
                Class<?> type = method.getDeclaringClass();
                MethodHandles.Lookup lookup = MethodHandles.lookup()
                    .in(type);
                Field allowedModesField = lookup.getClass().getDeclaredField("allowedModes");
                makeFieldModifiable(allowedModesField);
                allowedModesField.set(lookup, -1);
                return lookup
                    .unreflectSpecial(method, type)
                    .bindTo(proxy)
                    .invokeWithArguments(args);
            }
        }

        private static void makeFieldModifiable(Field field) throws Exception {
            field.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        }

    }

    default T base() {
        return null;
    }

    static <E extends Extension<T>, T> E create(Class<E> type, T instance) {
        if (type.isInterface()) {
            ExtensionHandler<T> handler = new ExtensionHandler<T>(instance);
            List<Class<?>> interfaces = new ArrayList<Class<?>>();
            interfaces.add(type);
            Class<?> baseType = type.getSuperclass();
            while (baseType != null && baseType.isInterface()) {
                interfaces.add(baseType);
                baseType = baseType.getSuperclass();
            }
            Object proxy = Proxy.newProxyInstance(
                    Extension.class.getClassLoader(),
                    interfaces.toArray(new Class<?>[interfaces.size()]),
                    handler);
            return type.cast(proxy);
        } else {
            return null;
        }
    }

}

1
यह एक कीचड़ का एक नरक है!
दिमित्री एवोन्टोमोव

1

एक डेकोरेटर ऑब्जेक्ट-ओरिएंटेड डिज़ाइन पैटर्न का उपयोग कर सकता है । जावा के मानक पुस्तकालय में उपयोग किए जा रहे इस पैटर्न का एक उदाहरण DataOutputStream होगा

सूची की कार्यक्षमता बढ़ाने के लिए यहां कुछ कोड दिए गए हैं:

public class ListDecorator<E> implements List<E>
{
    public final List<E> wrapee;

    public ListDecorator(List<E> wrapee)
    {
        this.wrapee = wrapee;
    }

    // implementation of all the list's methods here...

    public <R> ListDecorator<R> map(Transform<E,R> transformer)
    {
        ArrayList<R> result = new ArrayList<R>(size());
        for (E element : this)
        {
            R transformed = transformer.transform(element);
            result.add(transformed);
        }
        return new ListDecorator<R>(result);
    }
}

PS मैं कोटलिन का बहुत बड़ा प्रशंसक हूं । इसमें विस्तार के तरीके हैं और यह जेवीएम पर भी चलता है।


0

आप (RE) कलेक्शन इंटरफेस को लागू करके और Java कलेक्शन के लिए उदाहरण जोड़कर C # जैसे एक्सटेंशन / हेल्पर विधि बना सकते हैं:

public class RockCollection<T extends Comparable<T>> implements Collection<T> {
private Collection<T> _list = new ArrayList<T>();

//###########Custom extension methods###########

public T doSomething() {
    //do some stuff
    return _list  
}

//proper examples
public T find(Predicate<T> predicate) {
    return _list.stream()
            .filter(predicate)
            .findFirst()
            .get();
}

public List<T> findAll(Predicate<T> predicate) {
    return _list.stream()
            .filter(predicate)
            .collect(Collectors.<T>toList());
}

public String join(String joiner) {
    StringBuilder aggregate = new StringBuilder("");
    _list.forEach( item ->
        aggregate.append(item.toString() + joiner)
    );
    return aggregate.toString().substring(0, aggregate.length() - 1);
}

public List<T> reverse() {
    List<T> listToReverse = (List<T>)_list;
    Collections.reverse(listToReverse);
    return listToReverse;
}

public List<T> sort(Comparator<T> sortComparer) {
    List<T> listToReverse = (List<T>)_list;
    Collections.sort(listToReverse, sortComparer);
    return listToReverse;
}

public int sum() {
    List<T> list = (List<T>)_list;
    int total = 0;
    for (T aList : list) {
        total += Integer.parseInt(aList.toString());
    }
    return total;
}

public List<T> minus(RockCollection<T> listToMinus) {
    List<T> list = (List<T>)_list;
    int total = 0;
    listToMinus.forEach(list::remove);
    return list;
}

public Double average() {
    List<T> list = (List<T>)_list;
    Double total = 0.0;
    for (T aList : list) {
        total += Double.parseDouble(aList.toString());
    }
    return total / list.size();
}

public T first() {
    return _list.stream().findFirst().get();
            //.collect(Collectors.<T>toList());
}
public T last() {
    List<T> list = (List<T>)_list;
    return list.get(_list.size() - 1);
}
//##############################################
//Re-implement existing methods
@Override
public int size() {
    return _list.size();
}

@Override
public boolean isEmpty() {
    return _list == null || _list.size() == 0;
}

-7

Java8 अब डिफ़ॉल्ट विधियों का समर्थन करता है , जो कि C#विस्तार विधियों के समान हैं ।


9
गलत; इस प्रश्न में उदाहरण अभी भी असंभव है।
SLaks

@SLaks जावा और C # एक्सटेंशन में क्या अंतर है?
फाबियो मिल्हीरो

3
डिफ़ॉल्ट तरीकों को केवल इंटरफ़ेस के भीतर परिभाषित किया जा सकता है। docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
SLaks

दरवार, यह टिप्पणी धागा ही एकमात्र स्थान था जहाँ डिफ़ॉल्ट विधियों का उल्लेख किया गया था, जिसे मैं याद करने की सख्त कोशिश कर रहा था। उनका उल्लेख करने के लिए धन्यवाद, अगर नाम से नहीं! :-) (लिंक के लिए साभार @SLaks)
jpaugh

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