java अनाम वर्ग का उपयोग करने में क्या नुकसान है?




anonymous-class (5)

यह प्रदर्शन, या ऐसा कुछ भी कहने में प्रति खराब दृष्टिकोण नहीं है, लेकिन दृष्टिकोण थोड़ा अस्पष्ट है और इस तरह से कुछ का उपयोग करते समय, आपको हमेशा (कहते हैं, 99%) इस दृष्टिकोण को समझाना होगा। मुझे लगता है कि इस दृष्टिकोण का उपयोग न करने के सबसे बड़े कारणों में से एक है, और टाइप करते समय:

List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);

थोड़ा अधिक टाइपिंग है, इसे पढ़ना थोड़ा आसान है, जो कोड को समझने या डीबग करने में बहुत मदद करता है।

इस प्रश्न का उत्तर पढ़ते हुए प्रश्न उत्पन्न हुआ - मैं जावा में दो सूचियों को कैसे जोड़ूँ । इस answer ने समाधान दिया

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };

टिप्पणियों को पढ़ते हुए, उपयोगकर्ताओं ने कहा कि यह बुराई और बदसूरत था और इसका उपयोग उत्पादन में नहीं किया जाना चाहिए।

मैं यह जानना चाहूंगा कि इसका उपयोग करने में क्या नुकसान है? उत्पादन में उपयोग करना बदसूरत, बुरा या बुरा क्यों है?

नोट: इसे एक प्रश्न के रूप में पूछा गया है, क्योंकि संदर्भित पोस्ट बहुत पुरानी है (2008) और उत्तरदाता कई महीनों से दूर है।


क्योंकि आपको एक अलग उपवर्ग की आवश्यकता नहीं है - आपको बस सामान्य वर्ग का एक नया ArrayList बनाने की आवश्यकता है, और addAll() सूचियाँ addAll() दोनों जोड़ें।

इस तरह:

public static List<String> addLists (List<String> a, List<String> b) {
    List<String> results = new ArrayList<String>();
    results.addAll( a);
    results.addAll( b); 
    return results;
}

यह एक उपवर्ग बनाने के लिए बुराई है, जिसकी आवश्यकता नहीं है। आपको विस्तार या उपवर्ग व्यवहार की आवश्यकता नहीं है - बस डेटा मान बदलें।


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

स्रोत कोड के एक उदाहरण टुकड़े को देखते हुए:

public interface Inner {
    void innerAction();
}

public class Outer {

    public void methodInOuter() {}

    private Inner inner = new Inner() {
        public void innerAction() {
            // calling a method outside of scope of this anonymous class
            methodInOuter();  
        }
    }
}

संकलन के समय क्या होता है, यह है कि कंपाइलर Inner के नए गुमनाम उपवर्ग के लिए एक वर्ग फ़ाइल बनाता है जिसे Outer वर्ग के उदाहरण के संदर्भ में एक तथाकथित सिंथेटिक क्षेत्र मिलता है। उत्पन्न बाइटकोड कुछ इस तरह से लगभग बराबर होगा:

public class Outer$1 implements Inner {

    private final Outer outer; // synthetic reference to enclosing instance

    public Outer$1(Outer outer) {
        this.outer = outer;
    }

    public void innerAction() {
        // the method outside of scope is called through the reference to Outer
        outer.methodInOuter();
    }
}

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

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

एक संभावित समाधान केवल स्थिर विधियों में डीबीआई का उपयोग करना होगा, क्योंकि उनके दायरे में ऐसा कोई संलग्न उदाहरण उपलब्ध नहीं है।

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

public static <T> List<T> join(List<? extends T> first, List<? extends T> second) {
    List<T> joined = new ArrayList<>();
    joined.addAll(first);
    joined.addAll(second);
    return joined;
}

और फिर ग्राहक कोड बस बन जाता है:

List<String> newList = join(listOne, listTwo);

आगे पढ़े: https://.com/a/924536/1064809


अनाम वर्गों के इस विशेष उपयोग में कई समस्याएं हैं:

  1. यह एक अल्पज्ञात मुहावरा है। जो डेवलपर्स इसे नहीं जानते हैं (या यह जानते हैं कि यह इसका उपयोग नहीं करता है) को पढ़ने और / या इसे संशोधित करने वाले कोड को संशोधित करते समय धीमा कर दिया जाएगा।
  2. यह वास्तव में एक भाषा की सुविधा का दुरुपयोग कर रहा है: आप एक नए प्रकार के ArrayList को परिभाषित करने की कोशिश नहीं कर रहे हैं, आप बस कुछ सरणी सूची चाहते हैं जिसमें कुछ महत्वपूर्ण मान हैं
  3. यह एक नया वर्ग बनाता है जो संसाधन लेता है: वर्ग परिभाषा रखने के लिए डिस्क स्थान, पार्स करने के लिए समय / सत्यापन / ... यह, वर्ग परिभाषा धारण करने के लिए, परमिट ...
  4. यहां तक ​​कि अगर "वास्तविक कोड" थोड़ा लंबा है, तो इसे आसानी से एक उपयुक्त नाम उपयोगिता विधि ( joinLists(listOne, listTwo) ) में स्थानांतरित किया जा सकता है

मेरी राय में # 1 इससे बचने का सबसे महत्वपूर्ण कारण है, इसके बाद # 2 है। # 3 आमतौर पर समस्या का इतना हिस्सा नहीं है, लेकिन इसे नहीं भूलना चाहिए।


आपके उदाहरण में यह वास्तव में बुराई और कुरूप दिखता है, कम से कम मेरे लिए - यह समझना मुश्किल है कि कोड में क्या हो रहा है। लेकिन अनाम कक्षाओं का उपयोग करने के कुछ पैटर्न हैं जो लोगों के लिए उपयोग किए जाते हैं क्योंकि वे उन्हें अक्सर, उदा

    Arrays.sort(args, new Comparator<String>() {
        public int compare(String o1, String o2) {
            return  ... 
        }});

मैं ऊपर एक सबसे अच्छा अभ्यास मामला कहूंगा।





anonymous-class