2015-09-20 5 views
5

जबकि पॉलिमॉर्फिज्म का मुख्य सिद्धांत types की अवधि में "किस से" है, लेकिन मुझे क्या भ्रमित करता है कि विधि-कॉल तंत्र कैसे पाता है और पॉलिमॉर्फिज्म में सही विधि निकाय को कॉल करता है।Java Determine विधियों को polymorphism में रनटाइम पर कैसे कॉल करता है?

के बाद से जावा में सभी विधि बाध्यकारी late-binding है, जब तक विधि static, final या private है, और देर से बाध्यकारी JVM जो प्रत्येक वर्ग के लिए method table precomputes और फिर एक मेज सामान्य विधि कॉल में रनटाइम के दौरान ऊपर देखो करना द्वारा किया जाता है।

लेकिन यह भी पॉलिमॉर्फिज्म के दौरान होता है। उदाहरण

मान लीजिए के लिए मैं एक ride() विधि

class Cycle { 

    public void ride(){ 
     System.out.println("I'm Riding generic Cycle()"); 
    } 

} 

के साथ एक सामान्य वर्ग Cycle है और मैं तीन विशेष कक्षा BicycleTricycle और Unicycle जो सामान्य वर्ग Cycle प्रदान करता है और अपने ride() विधि को ओवरराइड करता है।

class Bicycle extends Cycle { 

    public void ride() { 
     System.out.println("I'm riding Bicycle"); 

    } 

} 

class Tricycle extends Cycle{ 

    public void ride() { 
     System.out.println("I'm riding Tricycle "); 

    } 

} 

class Unicycle extends Cycle { 

    public void ride() { 
     System.out.println("I'm Riding Unicycle "); 

    } 

} 

यह TestRide श्रेणी से ऊपर बहुरूपता का परीक्षण करने के लिए है।

public static void main(java.lang.String[]); 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=2, locals=5, args_size=1 
     0: new   #17     // class com/polymorphism/Cycle 
     3: dup 
     4: invokespecial #24     // Method com/polymorphism/Cycle." 
<init>":()V 
     7: astore_1 
     8: aload_1 
     9: invokestatic #25     // Method ride:(Lcom/polymorphism/ 
Cycle;)V 
     12: new   #27     // class com/polymorphism/Bicycle 
     15: dup 
     16: invokespecial #29     // Method com/polymorphism/Bicycle 
."<init>":()V 
     19: astore_2 
     20: aload_2 
     21: invokestatic #25     // Method ride:(Lcom/polymorphism/ 
Cycle;)V 
     24: new   #30     // class com/polymorphism/Tricycle 

     27: dup 
     28: invokespecial #32     // Method com/polymorphism/Tricycl 
e."<init>":()V 
     31: astore_3 
     32: aload_3 
     33: invokestatic #25     // Method ride:(Lcom/polymorphism/ 
Cycle;)V 
     36: new   #33     // class com/polymorphism/Unicycle 

     39: dup 
     40: invokespecial #35     // Method com/polymorphism/Unicycl 
e."<init>":()V 
     43: astore  4 
     45: aload   4 
     47: invokestatic #25     // Method ride:(Lcom/polymorphism/ 
Cycle;)V 
     50: return 

भी बाईटकोड में अपनी बस invokestatic और invokespecial साथ सामान्य विधि कॉल के रूप में जब मैं सोचा था कि यह invokedynamic आंकड़ा करने के लिए प्रयोग करेंगे:

public class TestRide { 

    public static void ride(Cycle c){ 
     c.ride(); 
    } 

    public static void main(String[] args){ 

     Cycle Cycling = new Cycle(); 
     ride(Cycling); 

     Bicycle bi = new Bicycle(); 
     ride(bi); 

     Tricycle tri = new Tricycle(); 
     ride(tri); 

     Unicycle uni = new Unicycle(); 
     ride(uni); 
    } 

} 

आउटपुट

I'm Riding generic Cycle() 
I'm riding Bicycle 
I'm riding Tricycle 
I'm Riding Unicycle 

बाइट कोड है उस विधि के संस्करण को बाहर करें जो वस्तु के वास्तविक प्रकार के लिए उपयुक्त है। लेकिन बात वो नहीं थी।

तो कैसे जावा बहुरूपता के दौरान वास्तविक विधि कॉल यह पता लगाने करता है, जबकि हम सिर्फ TestRide कक्षा में ride() विधि ride(bi) की तरह में एक upcasted वस्तु पारित?

संपादित करें: दी राइड विधि बाईटकोड

public static void ride(com.polymorphism.Cycle); 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=1, locals=1, args_size=1 
     0: aload_0 
     1: invokevirtual #16     // Method com/polymorphism/Cycle.r 
ide:()V 
     4: return 
+1

शायद आपका परीक्षण केस बहुत आसान है। यदि जावा कंपाइलर संकलन-समय पर जानता है, तो किस विधि को बुलाया जाएगा, बाइटकोड की कोई आवश्यकता नहीं है जो गतिशील रूप से कुछ भी करता है। – mastov

+1

'invokedynamic' को गतिशील विधि लुकअप के लिए जेवीएम बाइटकोड में पेश किया गया था जो * जावा की विधि लुकअप का पालन नहीं करता है। जावा कंपाइलर इसका उपयोग क्यों करेगा? वर्चुअल विधि प्रेषण 'invokevirtual' और' invokeinterface' के साथ किया जाता है। ध्यान दें कि जावा कंपाइलर निश्चित रूप से 'invokedynamic' का उपयोग करने के लिए स्वतंत्र है यदि वह चाहता है। जावा लैंग्वेज स्पेसिफिकेशन जावा के संकलन के बारे में कुछ भी नहीं कहता है, यह भी नहीं कहता कि इसे संकलित किया जाना चाहिए, यह भी व्याख्या की जा सकती है। –

+0

@ JörgWMittag अपना अंक मिला :)। लेकिन यह सवाल अभी भी –

उत्तर

0

मुझे लगता है कि पहले से ही @JBNizet समाधान पता लगा टिप्पणियों में (और मेरा अनुमान निकला गलत होने के लिए)। लेकिन जब से वह एक जवाब के रूप में पोस्ट नहीं है, मैं यह करूँगा:

main विधि किसी भी गतिशील व्यवहार है क्योंकि यह हमेशा कभी कॉल करने के लिए जा रहा है दिखाने के लिए नहीं होना चाहिए है कि एकएकल विधि TestRide.ride(Cycle c)। कोई अन्य संभव तरीका नहीं है, इसलिए पता लगाने के लिए कुछ भी नहीं है।

गतिशील विधि कॉल उस विधि TestRide.ride(Cycle c) के अंदर है। और अब जब आपने वह कोड पोस्ट किया है, तो वास्तव में हम invokevirtual का उपयोग करके गतिशील विधि प्रेषण देखते हैं। तो, आखिरकार, कोई आश्चर्य नहीं। गतिशील विधि प्रेषण वहाँ है।

1

पहले invokedynamic जावा 8 लैम्बडास और गैर-जावा कोड के लिए है, तो आप इसके बारे में भूल सकते हैं।कि से

अलावा, चार आह्वान निर्देश (invokespecial, invokestatic, invokevirtual, और invokeinterface) कर रहे हैं। आप JVM sepcification में सटीक अर्थशास्त्र देख सकते हैं, लेकिन नीचे पंक्ति यह है कि invokevirtual और invokeinterfaceवर्चुअल विधि कॉल हैं, यानी वास्तविक विधि को रनटाइम पर लक्ष्य के संक्षिप्त प्रकार के आधार पर चुना जाता है।

आपके कोड में एकमात्र वर्चुअल कॉल TestRide.ride में है। सूचीबद्ध लक्ष्य Cycle.ride:()V है। हालांकि, चूंकि यह वर्चुअल कॉल है, इसलिए JVM रनटाइम पर पहले तर्क के वास्तविक प्रकार की जांच करेगा और उस विधि के सबसे व्युत्पन्न संस्करण को कॉल करेगा।

यह सी ++ में वर्चुअल विधि कॉल के समान है, सिवाय इसके कि जेवीएम और जेआईटी संकलन के अमूर्तता ने अधिक अनुकूलित कार्यान्वयन की संभावना को अनुमति दी है।

यह भी ध्यान दें कि यह विधि अधिभार के साथ भ्रमित नहीं होना चाहिए, जो संकलन-समय बहुरूपता का एक रूप है। ओवरलोडेड विधियों के लिए, संकलक चुनता है कि तर्कों के संकलन समय प्रकार के आधार पर किसको कॉल करना है।

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