2014-06-22 7 views
6

जब किसी कन्स्ट्रक्टर के पास सुपर क्लास कन्स्ट्रक्टर (या this()) का स्पष्ट कॉल नहीं होता है तो संकलक super() सम्मिलित करता है।क्या होता है यदि मैं कक्षा फ़ाइल से सुपर कन्स्ट्रक्टर कॉल को हटा देता हूं?

क्या होगा यदि यह कॉल कक्षा फ़ाइल (संकलन के बाद) से हटा दी गई हो तो क्या होगा?

+3

शुरुआत के लिए अपरिभाषित व्यवहार। – EJP

+0

आप क्यों हासिल करना चाहते हैं? या तो सुपर क्लास के अन्य कन्स्ट्रक्टर को कॉल करता है या डिफ़ॉल्ट का उपयोग करता है और आपको कम से कम एक अन्य बुद्धिमान ऑब्जेक्ट को कॉल करने की आवश्यकता नहीं होती है। – Braj

+2

@ ब्राज मुझे लगता है कि यह बौद्धिक जिज्ञासा है, ऐसा करने के लिए कोई सौहार्दपूर्ण कारण नहीं है लेकिन परिणाम दिलचस्प हो सकते हैं कम से कम –

उत्तर

5

मैंने इसे स्वयं करने की कोशिश की।

class Test 
{ 
    public Test() 
    { 
     System.out.println("Hello World"); 
    } 

    public static void main(String[] args) 
    { 
     new Test() 
    } 
} 

मैं इसे संकलित और एक वर्ग फ़ाइल संपादक के साथ निर्माता से invokespecial java/lang/Object/<init>()V हटा दिया।

ऐसा लगता है JVM वर्ग लोड करने के लिए मना कर दिया की तरह:

Exception in thread "main" java.lang.VerifyError: Operand stack overflow 
Exception Details: 
    Location: 
    Test.<init>()V @4: ldc 
    Reason: 
    Exceeded max stack size. 
    Current Frame: 
    bci: @4 
    flags: { flagThisUninit } 
    locals: { uninitializedThis } 
    stack: { uninitializedThis, 'java/io/PrintStream' } 
    Bytecode: 
    0000000: 2ab2 0002 1203 b600 04b1 

     at java.lang.Class.getDeclaredMethods0(Native Method) 
     at java.lang.Class.privateGetDeclaredMethods(Unknown Source) 
     at java.lang.Class.getMethod0(Unknown Source) 
     at java.lang.Class.getMethod(Unknown Source) 
     at sun.launcher.LauncherHelper.validateMainClass(Unknown Source) 
     at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source) 

मैं अभी भी है कि यदि एक परिभाषित व्यवहार है पता नहीं है।

संपादित

Raedwald के अनुसार मैं भी ढेर में गड़बड़ी को बदलने के लिए है।

इसलिए मैंने aload_0 को भी हटा दिया जो सुपर कन्स्ट्रक्टर कॉल से पहले था।

अब मैं निम्न अपवाद प्राप्त करें:

getstatic java/lang/System/out Ljava/io/PrintStream; 
ldc "Message" 
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V 
aload_0 
invokespecial java/lang/Object/<init>()V 
return 

कौन सा काम किया:

Exception in thread "main" java.lang.VerifyError: Constructor must call super() 
or this() before return 
    Exception Details: 
    Location: 
    org/exolin/geno/Test.<init>()V @8: return 
    Reason: 
    Error exists in the bytecode 
    Bytecode: 
    0000000: b200 0212 03b6 0004 b1 

     at java.lang.Class.getDeclaredMethods0(Native Method) 
     at java.lang.Class.privateGetDeclaredMethods(Unknown Source) 
     at java.lang.Class.getMethod0(Unknown Source) 
     at java.lang.Class.getMethod(Unknown Source) 
     at sun.launcher.LauncherHelper.validateMainClass(Unknown Source) 
     at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source) 

यह तो मैं करने के लिए निर्माता निर्देश पुनर्क्रमित मुझे उत्सुक बनाया!

+0

"अधिकतम स्टैक आकार से अधिक।" स्टैक में हेरफेर करने के लिए कुछ आस-पास के बाइटकोड्स को छेड़छाड़ करने की भी आवश्यकता है। – Raedwald

+0

http://stackoverflow.com/questions/14633109/determining-in-the-bytecode-where-is-the-super-method-call-all-constructors-mu संबंधित प्रश्न है कि बाइटकोड के कौन से हिस्सों में हेरफेर करना है । – Raedwald

3

जावा भाषा स्तर पर क्या आवश्यक है और बाइटकोड स्तर पर क्या आवश्यक है, के बीच एक अंतर है, जो बहुत अधिक लक्सर है।

जावा भाषा स्तर पर, आपके पास पहले कथन के रूप में एक कन्स्ट्रक्टर कॉल होना चाहिए, लेकिन यदि आप इसे छोड़ देते हैं तो संकलक एक अंतर्निहित रूप से सम्मिलित होगा।

बाइटकोड स्तर पर, केवल आवश्यकता यह है कि सामान्य रूप से लौटने वाले प्रत्येक कोड पथ के साथ बिल्कुल एक कन्स्ट्रक्टर कॉल होता है, साथ ही प्रारंभिक से पहले this मान के साथ आप क्या कर सकते हैं पर प्रतिबंध हैं।

विशेष रूप से, इसका मतलब है कि

  • निर्माता कॉल विधि
  • आप सशर्त तर्क के आधार पर अलग अलग निर्माताओं बुला बीच चयन कर सकते की शुरुआत में प्रदर्शित करने के
  • आप हो सकता है नहीं है सुपरक्लस कन्स्ट्रक्टर
  • द्वारा फेंकने वाले अपवादों को शामिल करने वाले अपवाद हैंडलर सहित, यदि प्रत्येक कोड पथ अपवाद फेंकता है या अनंत लूप में जाता है तो आपके पास कोई कन्स्ट्रक्टर कॉल नहीं हो सकता है।

पहला विकल्प वास्तव में javac में प्रकट होता है, कोड उत्पन्न क्योंकि जावा में, आप निर्माता कॉल करने के लिए तर्क के रूप में एक अभिव्यक्ति पारित कर सकते हैं, और कोड की गणना करने के कि अभिव्यक्ति स्पष्ट रूप से निर्माता कहा जाता है से पहले होता है।लेकिन उन शेष विकल्पों को जावा में पूरा करना असंभव है।

ध्यान दें कि यदि आप इन प्रतिबंधों का उल्लंघन करते हैं, तो क्या होगा यदि आप सामान्य जावा कन्स्ट्रक्टर से कन्स्ट्रक्टर कॉल को हटाते हैं जो सामान्य रूप से लौटाता है, तो कन्स्ट्रक्टर अब अमान्य हो जाएगा क्योंकि यह लौटाता है लेकिन इसमें कोई सीटीओआर कॉल नहीं है। इस प्रकार, वर्ग को लोड करने का प्रयास VerifyError के साथ रनटाइम पर विफल हो जाएगा।

पूर्णता के लिए, आप एक अनियमित this मान के साथ क्या कर सकते हैं: इसे उसी वर्ग में परिभाषित फ़ील्ड को शून्य, और स्टोर (लेकिन पढ़ा नहीं गया) के साथ तुलना करें।

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

3

नवीनतम JVM कल्पना 4.9.2 Structural Constraints अनुभाग में इस का कहना है:

"प्रत्येक उदाहरण प्रारंभ विधि, वर्ग वस्तु के निर्माता से प्राप्त उदाहरण प्रारंभ विधि के अलावा, दोनों में से किसी एक और उदाहरण प्रारंभ विधि कॉल करना होगा इसके उदाहरण सदस्यों से पहले पहुंचने से पहले या इसके प्रत्यक्ष सुपरक्लास सुपर की एक इंस्टेंस प्रारंभिक विधि। "

दूसरे शब्दों में, यदि आप invokespecial <init> अनुदेश अनुक्रम निर्माता के super(...) या this(...) कॉल करने के लिए इसी निकालें, तब वर्ग फ़ाइल अमान्य है, और सत्यापनकर्ता यह पता लगा लेगा।

(और @Jimmy टी की जांच के अनुसार, यह करता है!)

इस बाधा के पीछे तर्क अन्य जवाब द्वारा समझाया गया है।

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