2010-07-19 13 views
7

मैं एक बाइटकोड उपकरण लिख रहा हूं। अभी, मैं यह पता लगाने की कोशिश कर रहा हूं कि वस्तुओं की उपस्थिति में इसे कैसे किया जाए। मैं दो पंक्तियों मैं JVMs में पढ़ा (खंड 4.9.4) पर कुछ स्पष्टीकरण चाहते हैं:बाइटकोड और ऑब्जेक्ट्स पर स्पष्टीकरण

1) "सत्यापनकर्ता कोड नई वस्तु से पहले यह किया गया है प्रारंभ का उपयोग करता है को खारिज कर दिया।"

मेरा सवाल है, "उपयोग" का अर्थ यहां क्या है? मैं अनुमान लगा रहा हूं कि इसका मतलब है: इसे एक विधि विशेषता के रूप में पास करना, GETFIELD और PUTFIELD पर कॉल करना, या उस पर किसी भी इंस्टेंस विधि को कॉल करना। क्या उनके अन्य वर्जित उपयोग हैं? और मेरा मानना ​​है कि यह DUP, LOAD और STORE जैसे अन्य निर्देशों का पालन करता है।

2) "उस विधि myClass का एक और उदाहरण प्रारंभ विधि या इस पर इसके प्रत्यक्ष सुपर क्लास, केवल आपरेशन विधि क्षेत्रों myClass भीतर घोषित बताए है इस पर प्रदर्शन कर सकते हैं का आह्वान करने से पहले।"

जिसका मतलब है कि एक <init> विधि में, GETFIELD और PUTFIELD एक और <init> कहा जाता है से पहले अनुमति दी जाती है। हालांकि, जावा में, super() या this() पर कॉल से पहले एक उदाहरण फ़ील्ड पर किसी भी ऑपरेशन को संकलन त्रुटि में परिणाम देता है। क्या कोई इसे स्पष्ट कर सकता है?

3) मेरे पास एक और सवाल है। ऑब्जेक्ट संदर्भ कब प्रारंभ होता है, और इसलिए, स्वतंत्र रूप से उपयोग करने के लिए तैयार है? जेवीएमएस पढ़ने से, मैं जवाब के साथ आया कि क्या एक वस्तु शुरू की गई है या नहीं, प्रत्येक विधि तक है। समय में एक निश्चित बिंदु पर, वस्तु को विधि के लिए शुरू किया जा सकता है लेकिन दूसरे के लिए नहीं। विशेष रूप से, उस विधि के लिए एक ऑब्जेक्ट प्रारंभ होता है जब उस विधि रिटर्न द्वारा <init> कहा जाता है।

उदाहरण के लिए, मान लें कि main() विधि ने एक ऑब्जेक्ट बनाया और <init> कहा जिसे बाद में सुपरक्लास के <init> कहा जाता है। super() से लौटने के बाद, ऑब्जेक्ट को अब <init> द्वारा प्रारंभ किया गया है, लेकिन अभी तक main() के लिए प्रारंभ नहीं किया गया है। इसका मतलब है, <init> में super() के बाद, मैं ऑब्जेक्ट को एक विधि के पैरामीटर के रूप में पास कर सकता हूं, यहां तक ​​कि मुख्य() से लौटने से पहले भी।

क्या कोई यह पुष्टि कर सकता है कि यह संपूर्ण विश्लेषण सत्य है? आपके समय के लिए शुक्रिया।

ps: मैंने वास्तव में सूर्य मंचों पर एक ही प्रश्न पोस्ट किया है लेकिन प्रतिक्रिया के साथ। मुझे आशा है कि मुझे यहां और अधिक भाग्य मिलेगा। धन्यवाद।

अद्यतन

सबसे पहले अपने जवाब के लिए और समय के लिए धन्यवाद। हालांकि मुझे स्पष्ट जवाब नहीं मिला (मेरे पास कई प्रश्न थे और उनमें से कुछ थोड़ा अस्पष्ट थे), आपके उत्तर और उदाहरण, और बाद के प्रयोग, जेवीएम काम करता है और अधिक गहराई से समझने के लिए मेरे लिए बेहद उपयोगी थे।

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

एक आखिरी बात, एसओ रॉक्स !!! मैंने आधिकारिक सूर्य जेवीएम निर्दिष्टीकरण मंच में एक ही प्रश्न पोस्ट किया, और मुझे अब तक कोई जवाब नहीं मिला है।

उत्तर

1

मेरा सुझाव है कि आप ओपनजेडीके स्रोतों की एक प्रति डाउनलोड करें और देखें कि सत्यापनकर्ता वास्तव में क्या जांच रहा है। यदि कुछ और नहीं है, तो यह समझने में आपकी मदद कर सकता है कि जेएमवी विनिर्देश क्या कह रहा है।

(हालांकि, @Joachim सही है। क्या बजाय क्या विनिर्देश कहते सत्यापनकर्ता कार्यान्वयन करता है बल्कि जोखिम भरा है पर निर्भर।)

+0

यह एक बुरा विचार नहीं है, लेकिन आप इस के साथ सावधान रहना चाहिए । अतीत में वास्तविक सत्यापनकर्ता विनिर्देशों के मुकाबले नियमों के बारे में कम सख्त होता था। यह पूरी तरह से संभव है कि ऐसे मामले अभी भी होते हैं। –

+0

हां, मैंने पाया कि सत्यापनकर्ता के विभिन्न कार्यान्वयन में कठोरता का अलग-अलग स्तर है। उदाहरण के लिए, अपाचे बीसीईएल का जस्टिस सत्यापनकर्ता स्टोर को अनियमित ऑब्जेक्ट रेफरेंस पर अनुमति नहीं देता है, जबकि जावा हॉटस्पॉट 10.0 –

4

"सत्यापनकर्ता कोड को खारिज कर दिया कि यह पहले नई वस्तु का उपयोग करता है शुरू किया गया है। "

बाइटकोड सत्यापन में, चूंकि सत्यापनकर्ता लिंक-टाइम पर काम करता है, विधियों के स्थानीय चर के प्रकार अनुमानित हैं। विधि तर्क के प्रकार ज्ञात हैं क्योंकि वे कक्षा फ़ाइल में विधि हस्ताक्षर में हैं। अन्य स्थानीय चर के प्रकार ज्ञात नहीं हैं और अनुमानित हैं, इसलिए मुझे लगता है कि उपरोक्त कथन में "उपयोग" "से संबंधित है।

संपादित करें: JVMS की धारा 4.9.4 पढ़ता है:

वर्ग MyClass के लिए उदाहरण के प्रारंभ विधि (§3.9) नई अप्रारंभीकृत ऑब्जेक्ट को उसके रूप में स्थानीय चर 0 में इस तर्क यह है कि विधि से पहले देखता है MyClass या इसके प्रत्यक्ष सुपरक्लास के एक और उदाहरण प्रारंभिक विधि को आमंत्रित करता है, इस पर एकमात्र ऑपरेशन विधि जो मेरे क्लास के भीतर घोषित फ़ील्ड असाइन कर रही है।

ऊपर बयान में खेतों की यह असाइनमेंट प्रारंभिक मानों पर "प्रारंभिक" उदाहरण चर के प्रारंभ जब वस्तु के लिए स्मृति आवंटित किया जाता है (पूर्णांक की तरह 0 है, नाव 0.0f आदि है)। वर्चुअल मशीन ऑब्जेक्ट पर इंस्टेंस प्रारंभिक विधि (कन्स्ट्रक्टर) का आह्वान करते समय इंस्टेंस चर के एक और "उचित" प्रारंभिकरण होता है।


जॉन होर्स्टमान द्वारा प्रदत्त link चीजों को स्पष्ट करने में मदद मिली। तो ये कथन सत्य नहीं हैं। "यह DOESNOT का मतलब है कि <init> विधि में, getfield और putfield को <init> से पहले अनुमति दी जाती है।" getfield और putfield निर्देशों का उपयोग कक्षा (उदाहरण के लिए) के आवृत्ति चर (फ़ील्ड्स) तक पहुंचने (और बदलने) के लिए किया जाता है। और यह केवल हो सकता है जब उदाहरण चर (क्षेत्र) प्रारंभ कर रहे हैं "

JVMs से:।

प्रत्येक उदाहरण प्रारंभ विधि (§3.9), उदाहरण के प्रारंभ विधि के लिए से प्राप्त छोड़कर वर्ग वस्तु की निर्माता, कॉल या तो इस का एक और उदाहरण प्रारंभ विधि या उसके उदाहरण के सदस्यों से पहले अपने प्रत्यक्ष सुपर क्लास सुपर के एक उदाहरण प्रारंभ विधि एक्सेस किया जाता है चाहिए। हालांकि, इस उदाहरण के वर्तमान उदाहरण में घोषित को इंस्टेंस प्रारंभिक विधि को कॉल करने से पहले असाइन किया जा सकता है।

जब जावा वर्चुअल मशीन, एक वर्ग का एक नया उदाहरण बनाता अनुमान से या स्पष्ट, यह पहली ढेर पर स्मृति आवंटित वस्तु के उदाहरण चर धारण करने के लिए। ऑब्जेक्ट की कक्षा में घोषित सभी चर के लिए मेमोरी आवंटित की जाती है और इसके सभी सुपरक्लास में, छुपाए गए आवृत्ति चर सहित। जैसे ही वर्चुअल मशीन ने एक नई ऑब्जेक्ट के लिए हीप मेमोरी को अलग कर दिया है, यह तुरंत इंस्टॉलेशन चर को डिफ़ॉल्ट प्रारंभिक मानों में प्रारंभ करता है। एक बार जब वर्चुअल मशीन ने नई ऑब्जेक्ट के लिए मेमोरी आवंटित की है और इंस्टॉलेशन चर को डिफ़ॉल्ट मानों में प्रारंभ किया है, तो यह आवृत्ति चर को उनके उचित प्रारंभिक मान देने के लिए तैयार है। जावा वर्चुअल मशीन यह करने के लिए दो तकनीकों का उपयोग करती है, इस पर निर्भर करता है कि क्लोन() आमंत्रण के कारण ऑब्जेक्ट बनाया जा रहा है या नहीं। यदि ऑब्जेक्ट क्लोन() के कारण बनाया जा रहा है, तो वर्चुअल मशीन ऑब्जेक्ट के आवृत्ति चर के मान को नई ऑब्जेक्ट में क्लोन किया जा रहा है। अन्यथा, वर्चुअल मशीन ऑब्जेक्ट पर एक इंस्टेंस प्रारंभिक विधि का आह्वान करती है। उदाहरण प्रारंभिक विधि ऑब्जेक्ट के आवृत्ति चर को उनके उचित प्रारंभिक मानों में प्रारंभ करती है। और इसके बाद आप getfield और putfield का उपयोग कर सकते हैं।

जावा कंपाइलर प्रत्येक वर्ग के लिए कम से कम एक उदाहरण प्रारंभिक विधि (कन्स्ट्रक्टर) उत्पन्न करता है। यदि कक्षा स्पष्ट रूप से कोई रचनाकार घोषित नहीं करती है, तो संकलक ने एक डिफ़ॉल्ट नो-एर्ग कन्स्ट्रक्टर उत्पन्न किया जो केवल सुपरक्लास नो-एर्ग कन्स्ट्रक्टर को आमंत्रित करता है। और ठीक है तो super() या this() पर कॉल से पहले एक उदाहरण फ़ील्ड पर किसी भी ऑपरेशन को संकलन त्रुटि में परिणाम दें। निर्माता के शरीर के लिए एक और <init> विधि की एक मंगलाचरण, कोड है कि किसी भी उदाहरण चर initializers लागू करता है, और कोड:

एक <init> विधि कोड के तीन प्रकार हो सकते हैं। एक निर्माता एक ही कक्षा में एक और निर्माता की एक स्पष्ट मंगलाचरण (एक this() मंगलाचरण) ने अपने इसी <init> विधि दो भागों से बना हो जाएगा से शुरू होता है:

  • एक ही श्रेणी की एक मंगलाचरण <init> विधि
  • bytecodes है कि शरीर इसी निर्माता

एक निर्माता एक this() मंगलाचरण के साथ शुरू नहीं होता है और वर्ग वस्तु नहीं है की लागू, <init> विधि तीन घटक होगा:

  • एक सुपर क्लास <init> विधि की एक मंगलाचरण
  • किसी भी उदाहरण के लिए bytecodes चर initializers
  • bytecodes कि इसी निर्माता के शरीर लागू


यदि कोई निर्माता this() इनवॉक से शुरू नहीं होता है एटियन और कक्षा ऑब्जेक्ट (और ऑब्जेक्ट में कोई सुपरक्लास नहीं है), उसके <init> विधि सुपरक्लास <init> विधि आमंत्रण के साथ शुरू नहीं हो सकती है। यदि कोई कन्स्ट्रक्टर सुपरक्लस कन्स्ट्रक्टर (super() आमंत्रण) के स्पष्ट आमंत्रण के साथ शुरू होता है, तो इसकी <init> विधि संबंधित सुपरक्लास <init> विधि का आह्वान करेगी।



मुझे लगता है कि यह आपके पहले और दूसरे प्रश्न का उत्तर देता है।

अपडेट किया गया:

उदाहरण के लिए,

class Demo 
    { 
    int somint; 

    Demo() //first constructor 
    { 
     this(5); 
     //some other stuff.. 
    } 

    Demo(int i) //second constructor 
    { 
     this.somint = i; 
     //some other stuff...... 
    } 
    Demo(int i, int j) //third constructor 
    { 
     super(); 
     //other stuffff...... 
    } 
    } 

यहाँ संकलक से ऊपर तीन निर्माताओं के लिए बाईटकोड (javac):

Demo(); 
    Code: 
    Stack=2, Locals=1, Args_size=1 
    0: aload_0 
    1: iconst_5 
    2: invokespecial #1; //Method "<init>":(I)V 
    5: return 

Demo(int); 
    Code: 
    Stack=2, Locals=2, Args_size=2 
    0: aload_0 
    1: invokespecial #2; //Method java/lang/Object."<init>":()V 
    4: aload_0 
    5: iload_1 
    6: putfield  #3; //Field somint:I 
    9: return 

Demo(int, int); 
    Code: 
    Stack=1, Locals=3, Args_size=3 
    0: aload_0 
    1: invokespecial #2; //Method java/lang/Object."<init>":()V 
    4: return 

पहले निर्माता में, <init> विधि समान श्रेणी <init> मेथ को कॉल करने के साथ शुरू होती है ओडी और फिर इसी रचनाकार के शरीर को निष्पादित किया। चूंकि कन्स्ट्रक्टर this() के साथ शुरू होता है, इसकी संबंधित <init> विधि में आवृत्ति चर प्रारंभ करने के लिए बाइटकोड नहीं होता है।

दूसरे निर्माता में, निर्माता के लिए <init> विधि

  • सुपर वर्ग <init> विधि, यानी है, सुपर क्लास निर्माता (कोई आर्ग विधि) की मंगलाचरण, संकलक यह डिफ़ॉल्ट द्वारा उत्पन्न क्योंकि पहले कथन के रूप में कोई स्पष्ट super() पाया गया था।
  • इंस्टेंस वैरिएबल someint प्रारंभ करने के लिए बाइटकोड।
  • कन्स्ट्रक्टर बॉडी में शेष सामग्री के लिए बाइटकोड।
+0

पीएस है: मैंने एक बाइटकोड उपकरण स्वयं लिखा है लेकिन मैं हाल ही में JVM के अंदर JVM पर सामान पढ़ रहा हूं। – Zaki

+0

सबसे पहले आपके समय के लिए धन्यवाद !!! मेरे पास अभी भी कुछ प्रश्न हैं: आपने कहा कि इस के साथ एक कन्स्ट्रक्टर() में 3 घटक हैं। हालांकि, मैंने बाइटकोड पढ़ा है, और संकलक कभी वैरिएबल प्रारंभकर्ताओं (int के लिए 0, वस्तुओं के लिए शून्य) के लिए बाइटकोड जोड़ता है। ऐसा लगता है कि JVM उदाहरण फ़ील्ड को बाइटकोड की आवश्यकता के बिना प्रारंभ करता है जो स्पष्ट रूप से ऐसा करता है। –

+0

@HH, अद्यतन उत्तर – Zaki

3

क्या जावा भाषा निर्दिष्ट करता है, बाईटकोड स्तर यह पर के विपरीत सुपर क्लास निर्माता कॉल करने से पहले एक निर्माता में एक वर्ग के क्षेत्रों तक पहुँचने के लिए संभव है। निम्नलिखित कोड इस तरह के एक वर्ग बनाने के लिए एएसएम लाइब्रेरी का उपयोग करता:

package asmconstructortest; 

import java.io.FileOutputStream; 
import org.objectweb.asm.*; 
import org.objectweb.asm.util.CheckClassAdapter; 
import static org.objectweb.asm.Opcodes.*; 

public class Main { 

    public static void main(String[] args) throws Exception { 
     //ASMifierClassVisitor.main(new String[]{"/Temp/Source/asmconstructortest/build/classes/asmconstructortest/Test.class"}); 
     ClassWriter cw = new ClassWriter(0); 
     CheckClassAdapter ca = new CheckClassAdapter(cw); 

     ca.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "asmconstructortest/Test2", null, "java/lang/Object", null); 

     { 
      FieldVisitor fv = ca.visitField(ACC_PUBLIC, "property", "I", null, null); 
      fv.visitEnd(); 
     } 

     { 
      MethodVisitor mv = ca.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 
      mv.visitCode(); 
      mv.visitVarInsn(ALOAD, 0); 
      mv.visitInsn(ICONST_1); 
      mv.visitFieldInsn(PUTFIELD, "asmconstructortest/Test2", "property", "I"); 
      mv.visitVarInsn(ALOAD, 0); 
      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); 
      mv.visitInsn(RETURN); 
      mv.visitMaxs(2, 1); 
      mv.visitEnd(); 
     } 

     ca.visitEnd(); 

     FileOutputStream out = new FileOutputStream("/Temp/Source/asmconstructortest/build/classes/asmconstructortest/Test2.class"); 
     out.write(cw.toByteArray()); 
     out.close(); 
    } 
} 

प्रारंभ इस वर्ग के ठीक काम करता है, किसी भी सत्यापन त्रुटियों के बिना:

package asmconstructortest; 

public class Main2 { 
    public static void main(String[] args) { 
     Test2 test2 = new Test2(); 
     System.out.println(test2.property); 
    } 
} 
+1

मैंने जेबे (जावा बाइटकोड संपादक) का उपयोग करके इस विचार का भी परीक्षण किया है और यह हॉटस्पॉट 10 सत्यापनकर्ता (लेकिन अपाचे बीसीईएल के जस्टिस पर नहीं) पर गुजरता है –

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