2016-04-19 12 views
14

मुझे पता है कि एक enumजावा में enum क्या अस्थिर बनाता है?

enum Year 
{ 
    First, Second, Third, Fourth; 
} 

final class Year extends Enum<Year> 
{ 
     public static final Year First = new Year(); 
     public static final Year Second = new Year(); 
     public static final Year Third = new Year(); 
     public static final Year Fourth = new Year(); 
} 

में परिवर्तित हो जाती जब मैं enum (नहीं वर्ग) मैं समय त्रुटि संकलन मिल का दृष्टांत करने की कोशिश की:

error: enum types may not be instantiated 
     Year y = new Year(); 

के अनुसार मेरा ज्ञान एक निजी कन्स्ट्रक्टर एक कक्षा को गैर तत्काल बनाता है। और मैंने सोचा कि संकलक एक निजी कन्स्ट्रक्टर प्रदान कर रहा है। लेकिन फिर मुझे उलझन में आया जब हमने देखा कि हम डिफॉल्ट संशोधक के साथ एनम के लिए एक कन्स्ट्रक्टर को परिभाषित कर सकते हैं और अभी भी टाइप एनम का ऑब्जेक्ट नहीं बना सकते हैं।

enum Year 
{ 
     First, Second, Third, Fourth; 
     Year() 
     { 
     } 
} 

class Example 
{ 
     public static void main(String[] args) 
     { 
       Year y = new Year(); 
     } 
} 

मेरा संदेह है, अगर यह रचनाकारों के बारे में नहीं है तो जावा में enum को तत्काल क्यों बनाया जाता है?

+8

"क्योंकि भाषा ऐसा कहती है।" वास्तव में, उससे कोई बेहतर जवाब नहीं है। आपकी 'enum' घोषणा चार ऑब्जेक्ट्स को _pre-created_ होने का कारण बनती है, और कक्षा के प्रत्येक ऑब्जेक्ट को उन चार में से एक होना चाहिए। तो किसी और को तुरंत चालू करने का कोई कारण नहीं है। – ajb

+1

साइड नोट: एक 'एनम वर्ष' को 'अंतिम श्रेणी वर्ष' में संकलित किया गया है, जो एनम 'बढ़ाता है। – Seelenvirtuose

उत्तर

19

यह Java Language Specification में निर्दिष्ट किया जाता:

8.9. Enum Types

...

एक enum प्रकार अपने enum स्थिरांक द्वारा परिभाषित के अलावा अन्य कोई उदाहरण नहीं है। यह एक enum प्रकार (§15.9.1) को स्पष्ट रूप से तत्काल करने का प्रयास करने के लिए एक संकलन-समय त्रुटि है।

इसलिए कंपाइलर सुनिश्चित करता है कि यह आवश्यकता पूरी हो गई है। चूंकि संकलक "जानता है" कि प्रकार enum है, यह enum Year और final class Year के बीच अंतर कर सकता है।

इसके अलावा, कोई पहुँच संशोधक एक enum निर्माता के लिए अनुमति दी है:

8.9.2. Enum Body Declarations

...

यह एक संकलन समय त्रुटि है अगर एक enum घोषणा में एक निर्माता घोषणा है सार्वजनिक या संरक्षित।

...

एक enum घोषणा में, पहुँच नहीं संशोधक के साथ एक निर्माता घोषणा निजी है।

तो, व्यावहारिक रूप से, enum कन्स्ट्रक्टर पैकेज-स्कॉप्ड (कोई एक्सेस संशोधक) जैसा दिखता है, लेकिन यह वास्तव में निजी है।

अंत में, एक ही अनुभाग में यह भी कहा

कोई निर्माता घोषणाओं के साथ एक enum घोषणा में, डिफ़ॉल्ट निर्माता परोक्ष घोषित किया जाता है। डिफ़ॉल्ट कन्स्ट्रक्टर निजी है, इसमें कोई औपचारिक पैरामीटर नहीं है, और इसमें कोई फेंक नहीं है।

यह enum गैर instantiable भले ही कोई निर्माता स्पष्ट रूप से घोषित किया जाता है बनाता है।

+3

आपका उत्तर भी एक महत्वपूर्ण बिंदु भूल जाता है: यह केवल संकलन-समय की बात नहीं है: संकलक वास्तव में enum के लिए एक निजी कन्स्ट्रक्टर उत्पन्न करता है, जिससे इसे तुरंत चालू करना असंभव हो जाता है। 'Javap -c -p' का उपयोग करके आसानी से खोजने योग्य। –

+4

@ जेबी निजेट: लेकिन 'निजी' संशोधक को ओवरराइट न करें। सामान्य वर्गों के लिए, एक 'निजी' कन्स्ट्रक्टर एक ही कक्षा के भीतर या यहां तक ​​कि नेस्टेड कक्षाओं के भीतर भी नए उदाहरण बनाने की अनुमति देता है, लेकिन 'enum' प्रकारों के लिए, संकलक भी उस पर प्रतिबंध लगाता है। इसके अलावा, प्रतिबिंब 'कन्स्ट्रक्टर' उदाहरण 'एनम' तत्काल प्रयासों के लिए अतिरिक्त जांच करता है।लेकिन अगर आप प्रतिबिंब में काफी गहरी हैक करते हैं तो आपको उस चेक को बाईपास करने के तरीके मिलेंगे (और फिर, एक 'निजी' संशोधक या तो बाधा नहीं है) ... – Holger

5

जावा में enum में डिफ़ॉल्ट डिज़ाइनर होता है जब इसे परिभाषित नहीं किया जाता है और यह निजी है।

डिफ़ॉल्ट एक्सेस संशोधक के अलग-अलग क्षेत्रों में अलग-अलग अर्थ हैं। उदाहरण के लिए विधियों और फ़ील्ड के लिए क्लास डिफ़ॉल्ट एक्सेस संशोधक के अंदर package private है।

जहां एक इंटरफ़ेस डिफ़ॉल्ट पहुंच संशोधक के रूप में public का अर्थ है। असल में एक इंटरफ़ेस फ़ील्ड पर कोई अन्य संशोधक नहीं हो सकता है, इसलिए यह स्पष्ट रूप से सार्वजनिक है।

एक शीर्ष स्तर वर्ग पर यह निजी पैकेज

तो अपने प्रश्न का उत्तर यह इसलिए है क्योंकि संकलक इसलिए फैसला करता है (जहां केवल 2 पहुँच संशोधक public और डिफ़ॉल्ट पैकेज निजी अनुमति दी जाती है) है। कंपाइलर लेखक को भाषा विनिर्देश अनुबंध को बनाए रखना पड़ा।

आप यह सोचने में सही हैं कि यह सब कुछ के बाद एक सामान्य वर्ग है। जावा में प्रत्येक ऑब्जेक्ट ब्लूप्रिंट प्रकार एक वर्ग है जिसे java.lang.Class द्वारा दर्शाया जा सकता है। इंटरफेस, एनम्स, अमूर्त कक्षाओं, अज्ञात वर्गों, विधि स्थानीय कक्षाओं के लिए ये प्रतिबंध केवल संकलक द्वारा मान्य हैं।

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

enum में कन्स्ट्रक्टर रखने का उद्देश्य एक कॉल में स्थिरांक के फ़ील्ड सेट करने में सक्षम होना है। enum के अंदर सभी स्थिरांक enum वर्ग के उदाहरण हैं, इसलिए उनमें भी घोषित फ़ील्ड शामिल हैं।

enum Test 
{ 
    T1(1), // equivalent to public static final Test T1 = new Test(1); 
    T2(2); // equivalent to public static final Test T2 = new Test(2); 

    int id; 
    Test(int id) 
    { 
     this.id = id; 
    } 
} 

और अंत में bellow java -p Test.class

final class Test extends java.lang.Enum<Test> 
{ 
    public static final Test T1; 
    public static final Test T2; 
    int id; 
    private static final Test[] $VALUES; 
    public static Test[] values(); 
    public static Test valueOf(java.lang.String); 
    private Test(int); 
    static {}; 
} 

का उपयोग कर यह क्या होता है जब वर्ग को संकलित करता है की एक बेहतर समझ देना चाहिए द्वारा enum ऊपर के लिए decompiled कोड का उत्पादन होता है।

संबंधित मुद्दे