क्या इनवॉइस डायनामिक है और मैं इसका उपयोग कैसे करूं?


159

मैं उन सभी नई शांत विशेषताओं के बारे में सुनता रहता हूं, जिन्हें JVM में जोड़ा जा रहा है और उन शांत विशेषताओं में से एक है इनवॉकेन्डीम। मैं जानना चाहूंगा कि यह क्या है और यह जावा में चिंतनशील प्रोग्रामिंग को कैसे आसान या बेहतर बनाता है?

जवाबों:


165

यह एक नया जेवीएम निर्देश है जो एक कंपाइलर को कोड उत्पन्न करने की अनुमति देता है जो पहले की तुलना में एक शिथिल विनिर्देशन के साथ तरीकों को कॉल करता है - यदि आप जानते हैं कि " बतख टाइपिंग " क्या है, तो इनवॉकेन्डेसिक मूल रूप से बतख टाइपिंग की अनुमति देता है। एक जावा प्रोग्रामर के साथ आप ऐसा नहीं कर सकते हैं; यदि आप एक उपकरण निर्माता हैं, तो आप इसका उपयोग अधिक लचीली, अधिक कुशल JVM- आधारित भाषाओं के निर्माण के लिए कर सकते हैं। यहाँ एक बहुत प्यारी ब्लॉग पोस्ट है जो बहुत विस्तार देती है।


3
दिन-प्रतिदिन जावा प्रोग्रामिंग में, प्रतिबिंब को असामान्य रूप से तरीकों से आह्वान करने के लिए इस्तेमाल किया जाना असामान्य नहीं है meth.invoke(args)। तो कैसे invokedynamicसाथ फिट बैठता है meth.invoke?
डेविड के।

1
मैं जिस ब्लॉग पोस्ट के बारे में बात करता हूं MethodHandle, वह वास्तव में एक ही तरह की चीज है, लेकिन बहुत अधिक लचीलेपन के साथ। लेकिन इस सब में असली शक्ति जावा भाषा के अतिरिक्त नहीं आती है, बल्कि JVM की क्षमताओं में अन्य भाषाओं का समर्थन करने में है जो आंतरिक रूप से अधिक गतिशील हैं।
अर्नेस्ट फ्रेडमैन-हिल


1
ऐसा लगता है कि जावा 8 कुछ लैंबडास का अनुवाद करता है, invokedynamicजिसके उपयोग से यह प्रदर्शन योग्य हो जाता है (उन्हें एक अनाम आंतरिक-वर्ग में लपेटने की तुलना में जो शुरू करने से पहले लगभग एकमात्र विकल्प था invokedynamic)। जेवीएम के शीर्ष पर संभवतः बहुत सारी कार्यात्मक प्रोग्रामिंग भाषाएं एनॉन-इनर-क्लासेस के बजाय इसे संकलित करने का विकल्प चुनेंगी।
नादेर घनबरी

2
बस एक छोटी सी चेतावनी, 2008 से ब्लॉग पोस्ट निराशाजनक रूप से पुराना है और वास्तविक रिलीज़ स्थिति (2011) को प्रतिबिंबित नहीं करता है।
होल्गर

9

कुछ समय पहले, C # ने एक शांत सुविधा जोड़ी, C # के भीतर गतिशील वाक्यविन्यास

Object obj = ...; // no static type available 
dynamic duck = obj;
duck.quack(); // or any method. no compiler checking.

इसे चिंतनशील विधि कॉल के लिए सिंटैक्स चीनी के रूप में सोचें। इसमें बहुत दिलचस्प अनुप्रयोग हो सकते हैं। http://www.infoq.com/pretations/Statically-Dynamic-Typing-Neal-Gafter देखें

नील गेयर, जो C # के गतिशील प्रकार के लिए जिम्मेदार है, बस SUN से MS तक डिफेक्टेड है। इसलिए यह सोचना अनुचित नहीं है कि SUN के अंदर उन्हीं बातों पर चर्चा की गई थी।

मुझे याद है इसके तुरंत बाद, कुछ जावा दोस्त ने कुछ इसी तरह की घोषणा की

InvokeDynamic duck = obj;
duck.quack(); 

दुर्भाग्य से, सुविधा नहीं है जहाँ जावा 7 में पाया जाना है। बहुत निराश हैं। जावा प्रोग्रामर के लिए, उनके पास invokedynamicअपने कार्यक्रमों का लाभ उठाने का कोई आसान तरीका नहीं है ।


41
invokedynamicजावा प्रोग्रामर के लिए इस्तेमाल करने का कभी इरादा नहीं था । IMO यह जावा दर्शन को बिल्कुल भी फिट नहीं करता है। इसे गैर-जावा भाषाओं के लिए JVM फीचर के रूप में जोड़ा गया था।
मार्क पीटर्स

5
@ मार्क कभी भी किसके इरादे से नहीं गए? ऐसा नहीं है कि जावा भाषा की हस्तियों में एक स्पष्ट शक्ति संरचना है, या एक अच्छी तरह से परिभाषित सामूहिक "इरादा" है। भाषा दर्शन के लिए - यह काफी व्यवहार्य है, नील गैटर (देशद्रोही!) स्पष्टीकरण देखें: infoq.com/pretations/Statically-Dynamic-Typing-Neal-Gafter
irreputable

3
@मार्क याचिकाकर्ता: वास्तव में केवल सीधे पहुंच योग्य नहीं है, जावा प्रोग्रामर के लिए भी इनवॉइस डायनामिक है। यह जावा 8 के बंद होने का आधार है।
M प्लैटवेट

2
@ निर्विवाद: जेएसआर योगदानकर्ताओं द्वारा कभी इरादा नहीं। यह बता रहा है कि JSR का नाम "जावा प्लेटफॉर्म पर डायनामिक रूप से टाइप की गई भाषाओं में सहायक" है। जावा गतिशील रूप से टाइप की गई भाषा नहीं है।
मार्क पीटर्स

5
@ एम प्लैवोवेट: मैं क्लोजर के साथ तारीख तक नहीं रहा, लेकिन यह निश्चित रूप से क्लोजर के लिए एक पूर्ण आवश्यकता नहीं होगी। एक अन्य विकल्प जिस पर उन्होंने चर्चा की, वह अनाम आंतरिक वर्गों के लिए सिंटैक्टिक शुगर को बंद कर रहा था जो कि वीएम कल्पना परिवर्तन के बिना किया जा सकता था। लेकिन मेरा कहना यह था कि JSR का उद्देश्य जावा भाषा में गतिशील टाइपिंग लाना कभी नहीं था, यदि आप JSR को पढ़ते हैं तो यह बहुत स्पष्ट है।
मार्क पीटर्स

4

आह्वान करने से पहले समझने के लिए दो अवधारणाएं हैं।

1. स्टेटिक बनाम डायनामिन टाइपिंग

स्टेटिक - संकलित समय पर preforms प्रकार की जाँच (जैसे जावा)

डायनेमिक - प्रीफॉर्म टाइप रनिंग पर चेकिंग (जैसे जावास्क्रिप्ट)

टाइप चेकिंग यह सत्यापित करने की एक प्रक्रिया है कि एक प्रोग्राम टाइप सुरक्षित है, यह है, वर्ग और उदाहरण चर, विधि पैरामीटर, वापसी मान और अन्य चर के लिए टाइप की गई जानकारी की जाँच करना। उदाहरण के लिए, संकलन समय पर स्ट्रिंग, .. के बारे में जावा जानता है, जबकि जावास्क्रिप्ट में किसी वस्तु का प्रकार केवल रनटाइम पर निर्धारित किया जा सकता है

2. मजबूत बनाम कमजोर टाइपिंग

मजबूत - इसके संचालन के लिए दिए गए मूल्यों के प्रकारों पर प्रतिबंध निर्दिष्ट करता है (जैसे जावा)

कमजोर - एक ऑपरेशन के तर्कों को धर्मान्तरित (कास्ट) करता है यदि उन तर्कों में असंगत प्रकार होते हैं (जैसे विज़ुअल बेसिक)

यह जानते हुए कि जावा एक स्टेटिक और कमजोर टाइप है, आप जेवीएम पर डायनेमिक और स्ट्रांगली टाइप की गई भाषाओं को कैसे लागू करते हैं?

चालित कार्य प्रणाली लागू करने के बाद - एक विधि या फ़ंक्शन का सबसे उपयुक्त कार्यान्वयन चुन सकता है जो रनटाइम सिस्टम लागू करता है।

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

जावा 7 के साथ इनवॉल्ड डायनामिक पेश किया गया था।


4

मेरे जावा रिकॉर्ड्स लेख के हिस्से के रूप में , मैंने इनोक डायनामिक के पीछे की प्रेरणा के बारे में व्यक्त किया। आइए इंडी की किसी न किसी परिभाषा से शुरू करें।

पेश है इंडी

डायनामिक इनवॉइस टाइप करें (इसे इंडी के रूप में भी जाना जाता है ) जेएसआर 292 का हिस्सा था, जो डायनेमिक प्रकार की भाषाओं के लिए जेवीएम समर्थन को बढ़ाने के लिए थी। जावा 7 में इसकी पहली रिलीज़ के बाद, invokedynamicइसके java.lang.invokeसामान के साथ-साथ ओपकोड का उपयोग जेयूबी जैसी गतिशील JVM- आधारित भाषाओं द्वारा काफी किया गया है।

हालाँकि विशेष रूप से गतिशील भाषा समर्थन को बढ़ाने के लिए तैयार की गई indy, यह उससे कहीं अधिक प्रदान करती है। तथ्य की बात के रूप में, यह प्रयोग करने के लिए उपयुक्त है जहाँ एक भाषा डिजाइनर को गतिशील प्रकार की कलाबाजी से लेकर गतिशील रणनीतियों तक किसी भी प्रकार की गतिशीलता की आवश्यकता होती है!

उदाहरण के लिए, जावा 8 लैम्ब्डा एक्सप्रेशंस वास्तव में उपयोग करके कार्यान्वित किए जाते हैं invokedynamic, भले ही जावा एक स्टेटिकली टाइप की गई भाषा हो!

उपयोगकर्ता-निश्चित बाइटकोड

कुछ समय के लिए JVM ने चार विधि आह्वान प्रकारों का समर्थन किया: invokestaticस्थिर विधियों invokeinterfaceको कॉल करने के लिए , इंटरफ़ेस विधियों invokespecialको कॉल करने के लिए, कंस्ट्रक्टरों super()या निजी तरीकों invokevirtualको कॉल करने के लिए और उदाहरण के तरीकों को कॉल करने के लिए।

उनके मतभेदों के बावजूद, ये आह्वान प्रकार एक सामान्य विशेषता साझा करते हैं : हम उन्हें अपने तर्क से समृद्ध नहीं कर सकते । इसके विपरीत, invokedynamic हमें किसी भी तरह से मंगलाचरण प्रक्रिया बूटस्ट्रैप में सक्षम बनाता है। तब JVM सीधे बूटस्ट्रैप्ड विधि को कॉल करने का ध्यान रखता है।

इंडी कैसे काम करती है?

पहली बार JVM एक invokedynamicनिर्देश देखता है , यह एक विशेष स्थैतिक विधि को बूटस्ट्रैप विधि कहता है । बूटस्ट्रैप विधि जावा कोड का एक टुकड़ा है जिसे हमने वास्तविक-टू-इनवॉल्ड लॉजिक तैयार करने के लिए लिखा है:

यहां छवि विवरण दर्ज करें

तब बूटस्ट्रैप विधि का एक उदाहरण देता है java.lang.invoke.CallSite। यह CallSiteवास्तविक विधि का संदर्भ है, अर्थात MethodHandle

अब से, हर बार जेवीएम इस invokedynamicनिर्देश को फिर से देखता है , यह स्लो पाथ को छोड़ देता है और सीधे अंतर्निहित निष्पादन योग्य कहता है। JVM धीमी गति से रास्ता छोड़ना जारी रखता है जब तक कि कुछ बदल न जाए।

उदाहरण: जावा 14 रिकॉर्ड्स

जावा 14 Recordsउन वर्गों को घोषित करने के लिए एक अच्छा कॉम्पैक्ट सिंटैक्स प्रदान कर रहा है जो गूंगा डेटा धारक हैं।

इस सरल रिकॉर्ड को ध्यान में रखते हुए:

public record Range(int min, int max) {}

इस उदाहरण के लिए बाइटकोड कुछ इस तरह होगा:

Compiled from "Range.java"
public java.lang.String toString();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokedynamic #18,  0 // InvokeDynamic #0:toString:(LRange;)Ljava/lang/String;
         6: areturn

इसकी बूटस्ट्रैप विधि तालिका में :

BootstrapMethods:
  0: #41 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
     (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;
     Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;
     Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
    Method arguments:
      #8 Range
      #48 min;max
      #50 REF_getField Range.min:I
      #51 REF_getField Range.max:I

इसलिए रिकॉर्ड्स के लिए बूटस्ट्रैप विधि को कहा जाता है bootstrapजो java.lang.runtime.ObjectMethodsकक्षा में रहती है । जैसा कि आप देख सकते हैं, यह बूटस्ट्रैप विधि निम्नलिखित मापदंडों की अपेक्षा करती है:

  • MethodHandles.Lookupलुकअप संदर्भ ( Ljava/lang/invoke/MethodHandles$Lookupभाग) का प्रतिनिधित्व करने का एक उदाहरण ।
  • विधि नाम (यानी toString, equals, hashCode, आदि) बूटस्ट्रैप लिंक जा रहा है। उदाहरण के लिए, जब मूल्य है toString, बूटस्ट्रैप एक ConstantCallSite( CallSiteजो कभी नहीं बदलता है) लौटाएगा जो toStringइस विशेष रिकॉर्ड के लिए वास्तविक कार्यान्वयन की ओर इशारा करता है।
  • TypeDescriptorविधि (के लिए Ljava/lang/invoke/TypeDescriptor भाग)।
  • एक प्रकार का टोकन, अर्थात Class<?>, रिकॉर्ड क्लास प्रकार का प्रतिनिधित्व करता है। यह Class<Range>इस मामले में है।
  • एक अर्ध-बृहदान्त्र सभी घटक नामों की सूची को अलग करता है, अर्थात min;max
  • MethodHandleप्रति घटक एक । इस तरह से बूटस्ट्रैप विधि MethodHandleइस विशेष विधि के कार्यान्वयन के लिए घटकों के आधार पर बना सकती है ।

invokedynamicअनुदेश बूटस्ट्रैप विधि करने के लिए उन सभी तर्कों से गुजरता है। बूटस्ट्रैप विधि, बदले में, का एक उदाहरण देता है ConstantCallSite। यह ConstantCallSiteअनुरोधित विधि कार्यान्वयन का संदर्भ है, उदाहरण के लिए toString

क्यों Indy?

प्रतिबिंब एपीआई के विपरीत, java.lang.invokeJVM पूरी तरह से सभी इनवोकेशन के माध्यम से देख सकता है क्योंकि एपीआई काफी कुशल है। इसलिए, JVM सभी प्रकार के अनुकूलन लागू कर सकता है जब तक हम धीमे रास्ते से बचते हैं जितना संभव हो!

दक्षता तर्क के अलावा, इसकी सादगी केinvokedynamic कारण दृष्टिकोण अधिक विश्वसनीय और कम भंगुर है ।

इसके अलावा, जावा रिकॉर्ड्स के लिए जेनरेट किया गया बाइटकोड संपत्तियों की संख्या से स्वतंत्र है। तो, कम bytecode और तेजी से स्टार्टअप समय।

अंत में, मान लें कि जावा के एक नए संस्करण में एक नया और अधिक कुशल बूटस्ट्रैप विधि कार्यान्वयन शामिल है। साथ invokedynamic, हमारा ऐप बिना किसी सुधार के इस सुधार का लाभ उठा सकता है। इस तरह हमारे पास कुछ प्रकार के फॉरवर्ड बाइनरी कम्पेटिबिलिटी है । इसके अलावा, यह जिस डायनेमिक रणनीति के बारे में हम बात कर रहे थे!

अन्य उदाहरण

जावा रिकॉर्ड्स के अलावा, इन्वोक डायनामिक का उपयोग सुविधाओं को लागू करने के लिए किया गया है:

  • जावा 8+ में लैम्ब्डा एक्सप्रेशन: LambdaMetafactory
  • जावा 9+ में स्ट्रिंग कॉनटैनेशन: StringConcatFactory
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.