जावा जेनेरिक विधि को कैसे स्थिर बनाया जाए?


172

निम्नलिखित किसी एकल आइटम को एक सरणी में जोड़ने के लिए जावा जेनेरिक क्लास बनाने के लिए एक स्निपेट है। मैं एक स्थिर विधि से appendToArray कैसे बना सकता हूं। संकलित त्रुटियों में विधि हस्ताक्षर परिणाम के लिए स्थैतिक जोड़ना।

public class ArrayUtils<E> {

        public E[] appendToArray(E[] array, E item) {
            E[] result = (E[])new Object[array.length+1];
            result[array.length] = item;
            return result;
        }
}

आपको कौन सी संकलन संबंधी त्रुटियाँ हैं? इसके अलावा, क्यों न केवल मानक पुस्तकालय कंटेनरों में से एक का उपयोग करें?
कार्ल केनचेल

1
संकलित त्रुटि: मैं वास्तव में स्थिर संशोधक को गलत जोड़ रहा था .. संग्रह का उपयोग करना: हाँ एक संग्रह का उपयोग करना आदर्श होगा फिर भी सवाल संग्रह बनाम सरणी के बारे में नहीं है, मेरे उपयोग के मामले में एक सरणी की आवश्यकता है।
क्रिस जॉनसन

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

जवाबों:


283

केवल एक चीज जो आप कर सकते हैं वह है अपने हस्ताक्षर को बदलना

public static <E> E[] appendToArray(E[] array, E item)

महत्वपूर्ण विवरण:

सामान्य मूल्य जो रिटर्न वैल्यू से पहले होते हैं, वे हमेशा एक नए सामान्य प्रकार के वेरिएबल को पेश करते हैं (घोषित करते हैं)।

इसके अतिरिक्त, प्रकार ( ArrayUtils) और स्थिर तरीकों ( appendToArray) के बीच चर प्रकार एक दूसरे के साथ कभी हस्तक्षेप नहीं करते हैं।

तो, इसका क्या मतलब है: मेरे जवाब में <E>छिपाने Eसे ArrayUtils<E>अगर विधि नहीं होगा static। और <E>साथ कोई संबंध नहीं है Eसे ArrayUtils<E>

इस तथ्य को बेहतर ढंग से प्रतिबिंबित करने के लिए, एक अधिक सही उत्तर होगा:

public static <I> I[] appendToArray(I[] array, I item)

30
कृपया यह भी ध्यान रखें कि वर्ग-स्तरीय प्रकार चर Eऔर स्थिर विधि प्रकार चर के बीच कोई संबंध नहीं है E। जेनेरिक विधियों, स्थिर या अन्यथा, जेनेरिक कक्षाओं के अंदर घोषणा करते समय एक अलग चर नाम का उपयोग करने के लिए मैं इसे बेहतर अभ्यास मानता हूं।
जज मेंटल

लेकिन इस मामले में मैं अलग-अलग प्रकार की एक वस्तुओं को पारम्स में पारित कर सकता हूं। जैसे मैं पहले पैराम और डबल आइटम के रूप में इंटेगर [] सरणी पास कर सकता हूं।
गुलाबीपन

Pinkpanther: सच है, लेकिन यह कोई नुकसान नहीं करता है, क्योंकि स्थैतिक विधि केवल एक सरणी ऑब्जेक्ट पर संचालित होती है जो इसे एक पैरामीटर के माध्यम से पारित किया जाता है, इसलिए इसके तत्वों का सही प्रकार होना निश्चित है।
डब्बल

80
public static <E> E[] appendToArray(E[] array, E item) { ...

ध्यान दें <E>

स्टेटिक जेनेरिक विधियों को अपने स्वयं के सामान्य घोषणा ( public static <E>) को वर्ग की सामान्य घोषणा ( public class ArrayUtils<E>) से अलग करने की आवश्यकता होती है ।

यदि संकलक एक स्थिर सामान्य विधि (फिर से आपके मामले में, लेकिन आमतौर पर, बस मामले में) की संभावना को लागू करने में एक प्रकार की अस्पष्टता के बारे में शिकायत करता है, तो यहां एक विशिष्ट प्रकार ( _class_.<_generictypeparams_>_methodname_) का उपयोग करके स्थैतिक सामान्य विधि को स्पष्ट रूप से कैसे लागू किया जाए :

String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");

यह केवल तभी होगा जब कंपाइलर जेनेरिक प्रकार का निर्धारण नहीं कर सकता है, क्योंकि जेनेरिक प्रकार विधि तर्कों से संबंधित नहीं है।


10

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

public class ArrayUtils {
    public static <T> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        result[array.length] = item;
        return result;
    }
}

1
यह काम नहीं करेगा क्योंकि आपने जेनेरिक प्रकार ई को परिभाषित नहीं किया है। इस मामले में आपके पास अभी भी जेनेरिक प्रकार <E> वर्ग परिभाषा में होना चाहिए।
जॉर्ज जेवियर

0

मैं इसे सरल तरीके से समझाता हूँ।

क्लास स्तर पर परिभाषित जेनरिक (स्टैटिक) विधि स्तर पर परिभाषित जेनरिक से पूरी तरह अलग हैं।

class Greet<T> {

    public static <T> void sayHello(T obj) {
        System.out.println("Hello " + obj);
    }
}

जब आप उपरोक्त कोड कहीं भी देखते हैं, तो कृपया ध्यान दें कि क्लास स्तर पर परिभाषित टी का स्थैतिक विधि में परिभाषित टी के साथ कोई लेना-देना नहीं है। निम्न कोड भी पूरी तरह से मान्य है और उपरोक्त कोड के बराबर है।

class Greet<T> {

    public static <E> void sayHello(E obj) {
        System.out.println("Hello " + obj);
    }
}

स्टैटिक विधि को क्लास के लोगों से अलग अपने जेनेरिक को अलग करने की आवश्यकता क्यों है?

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

इसलिए, जब भी आप स्थैतिक विधि को बुला रहे हैं,

Greet.sayHello("Bob");
Greet.sayHello(123);

जेवीएम निम्नलिखित के रूप में व्याख्या करता है।

Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);

दोनों एक ही आउटपुट दे रहे हैं।

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