2010-01-31 11 views
84

क्या कोई ओवरहेड है जब हम एक प्रकार की वस्तुओं को दूसरे प्रकार में डाल देते हैं? या संकलक बस सबकुछ हल करता है और रन टाइम पर कोई कीमत नहीं है?क्या जावा कास्टिंग ओवरहेड पेश करता है? क्यूं कर?

क्या यह एक सामान्य चीज है, या अलग-अलग मामले हैं?

उदाहरण के लिए, मान लें कि हमारे पास ऑब्जेक्ट [] का एक सरणी है, जहां प्रत्येक तत्व का एक अलग प्रकार हो सकता है। लेकिन हम हमेशा यह सुनिश्चित करने के लिए जानते हैं कि, कहते हैं, तत्व 0 एक डबल है, तत्व 1 एक स्ट्रिंग है। (मुझे पता है कि यह एक गलत डिजाइन है, लेकिन चलो बस मुझे यह करना है।)

क्या जावा की प्रकार की जानकारी अभी भी रन टाइम पर आसपास रखी गई है? या संकलन के बाद सब कुछ भूल गया है, और यदि हम (डबल) तत्व [0] करते हैं, तो हम केवल सूचक का पालन करेंगे और उन 8 बाइट्स को डबल के रूप में समझेंगे, जो कुछ भी है?

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

अंतर्निहित कास्टिंग जब आप एक व्यापक प्रकार है, जो स्वचालित रूप से किया जाता है करने के लिए एक प्रकार से डाली और वहाँ कोई भूमि के ऊपर है:

+0

उदाहरण और कास्टिंग का प्रदर्शन काफी अच्छा है। मैंने यहां समस्या के विभिन्न दृष्टिकोणों के आसपास जावा 7 में कुछ समय पोस्ट किया: http://stackoverflow.com/questions/16320014/java-optimization-nitpick-is-it-faster-to-cast-something-and-let-it- फेंक-एक्ससेप/28858680 # 28858680 – Wheezil

+0

इस अन्य प्रश्न के बहुत अच्छे जवाब हैं http://stackoverflow.com/questions/16741323/casting-performance-in- अलग-levels-when-casting-down – user454322

उत्तर

63

कास्टिंग के 2 प्रकार के होते हैं

String s = "Cast"; 
Object o = s; // implicit casting 

स्पष्ट कास्टिंग, जब आप एक व्यापक प्रकार से अधिक संकीर्ण होते हैं। इस मामले के लिए, आप स्पष्ट रूप से इस तरह कास्टिंग का उपयोग करना होगा:

Object o = someObject; 
String s = (String) o; // explicit casting 

इस दूसरे मामले में, वहाँ क्रम में भूमि के ऊपर है, क्योंकि दो प्रकार जाँच की जानी चाहिए और मामले में है कि कास्टिंग संभव नहीं है, JVM एक फेंक चाहिए ClassCastException। विशेष रूप से संदर्भ प्रकार के बीच, कास्टिंग आपरेशन के प्रकार है जिसमें हम यहाँ रुचि रखते हैं के लिए -

से JavaWorld: The cost of casting

कास्टिंग लिया प्रकार के बीच परिवर्तित करने के लिए प्रयोग किया जाता है।

Upcast परिचालन (भी जावा भाषा विशिष्टता में चौड़ा रूपांतरण कहा जाता है) एक पूर्वज वर्ग संदर्भ के लिए एक उपवर्ग संदर्भ परिवर्तित। यह कास्टिंग ऑपरेशन सामान्य रूप से स्वचालित होता है, क्योंकि यह हमेशा सुरक्षित रहता है और सीधे संकलक द्वारा लागू किया जा सकता है।

उदास परिचालन (भी जावा भाषा विशिष्टता में संकुचन रूपांतरण कहा जाता है) एक उपवर्ग संदर्भ के लिए एक पूर्वज वर्ग संदर्भ परिवर्तित। यह कास्टिंग ऑपरेशन निष्पादन ओवरहेड बनाता है, क्योंकि जावा के लिए यह सुनिश्चित करने के लिए कि यह मान्य है, रनटाइम पर कास्ट की जांच की आवश्यकता है। संदर्भित वस्तु या कलाकारों के लिए या तो लक्ष्य प्रकार प्रकार का एक उपवर्ग के उदाहरण नहीं है, तो प्रयास किया डाली की अनुमति नहीं है और एक java.lang.ClassCastException फेंक चाहिए।

+79

वह जावावर्ल्ड आलेख 10+ वर्ष है पुराना, इसलिए मैं आपके बेहतरीन नमक के बहुत बड़े अनाज के साथ प्रदर्शन के बारे में कोई बयान लेता हूं। – skaffman

+0

@ स्काफमैन, असल में मैं नमक के अनाज के साथ (चाहे प्रदर्शन के संबंध में) किसी भी बयान को लेता हूं। – Pacerier

+0

यह वही मामला होगा, अगर मैं संदर्भित जाति ऑब्जेक्ट को संदर्भ में निर्दिष्ट नहीं करता हूं और बस उस पर कॉल विधि करता हूं? जैसे '((स्ट्रिंग) ओ) .omeMethodOfCastedClass() ' –

7

उदाहरण के लिए, हम वस्तु [], प्रत्येक तत्व एक अलग प्रकार का हो सकता है, जहां की एक सरणी है। लेकिन हम हमेशा यह सुनिश्चित करने के लिए जानते हैं कि, कहते हैं, तत्व 0 एक डबल है, तत्व 1 एक स्ट्रिंग है। (मुझे पता है कि यह एक गलत डिजाइन है, लेकिन आइए मान लें कि मुझे यह करना है।)

कंपाइलर किसी सरणी के अलग-अलग तत्वों के प्रकारों को नोट नहीं करता है। यह बस जांचता है कि प्रत्येक तत्व अभिव्यक्ति का प्रकार सरणी तत्व प्रकार के लिए असाइन करने योग्य है।

क्या जावा की प्रकार की जानकारी अभी भी रन टाइम पर आसपास रखी गई है? या संकलन के बाद सब कुछ भूल गया है, और यदि हम (डबल) तत्व [0] करते हैं, तो हम केवल सूचक का पालन करेंगे और उन 8 बाइट्स को डबल के रूप में समझेंगे, जो कुछ भी है?

कुछ जानकारी रन टाइम पर चारों ओर रखी जाती है, लेकिन अलग-अलग तत्वों के स्थिर प्रकार नहीं। आप इसे कक्षा फ़ाइल प्रारूप को देखने से कह सकते हैं।

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

इसके अलावा, लोगों को वैसे भी आवेदन कोड नहीं लिखना चाहिए।

+0

primitives के बारे में क्या? '(फ्लोट) Math.toDegrees (theta) 'क्या यहां एक महत्वपूर्ण ओवरहेड भी होगा? –

+1

कुछ प्राचीन जानवरों के लिए एक उपर है। चाहे यह महत्वपूर्ण है संदर्भ पर निर्भर करता है। –

5

रनटाइम पर कास्टिंग करने के लिए बाइट कोड निर्देश checkcast कहा जाता है। निर्देशों को उत्पन्न करने के लिए आप javap का उपयोग कर जावा कोड को अलग कर सकते हैं।

सरणी के लिए, जावा रनटाइम पर प्रकार की जानकारी रखता है। अधिकांश समय, कंपाइलर आपके लिए प्रकार की त्रुटियों को पकड़ लेगा, लेकिन ऐसे मामले हैं जहां आप किसी ऑब्जेक्ट में किसी ऑब्जेक्ट को स्टोर करने का प्रयास करते समय ArrayStoreException में भाग लेंगे, लेकिन प्रकार मेल नहीं खाता है (और कंपाइलर इसे नहीं पकड़ता)। के बाद से ColoredPoint प्वाइंट का एक उपवर्ग है, लेकिन pa[0] = new Point() मान्य नहीं है

class Point { int x, y; } 
class ColoredPoint extends Point { int color; } 
class Test { 
    public static void main(String[] args) { 
     ColoredPoint[] cpa = new ColoredPoint[10]; 
     Point[] pa = cpa; 
     System.out.println(pa[1] == null); 
     try { 
      pa[0] = new Point(); 
     } catch (ArrayStoreException e) { 
      System.out.println(e); 
     } 
    } 
} 

Point[] pa = cpa मान्य है: Java language spec निम्न उदाहरण देता है।

यह सामान्य प्रकारों का विरोध है, जहां रनटाइम पर कोई प्रकार की जानकारी नहीं है। कंपाइलर जहां आवश्यक हो checkcast निर्देशों को सम्मिलित करता है।

जेनेरिक प्रकारों और सरणी के लिए टाइपिंग में यह अंतर अक्सर एरे और जेनेरिक प्रकारों को मिश्रण करने के लिए अनुपयुक्त बनाता है।

37

जावा का एक उचित कार्यान्वयन के लिए:

प्रत्येक वस्तु एक हेडर युक्त, अन्य बातों के साथ है, क्रम प्रकार के लिए सूचक (उदाहरण के Double या String के लिए, लेकिन यह CharSequence या AbstractList कभी नहीं हो सकता है)।रनटाइम कंपाइलर (आमतौर पर सूर्य के मामले में हॉटस्पॉट) को मानते हुए निर्धारित नहीं किया जा सकता है कि जेनरेट किए गए मशीन कोड द्वारा कुछ जांच की ज़रूरत है।

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

कक्षा के प्रकार को कास्टिंग करने के लिए, यह ज्ञात है कि जब तक आप java.lang.Object हिट नहीं करते हैं तब तक कितने सुपरक्लास हैं, इसलिए टाइप प्रकार पॉइंटर (वास्तव में हॉटस्पॉट में पहले आठ) से निरंतर ऑफसेट पर पढ़ा जा सकता है। फिर यह वर्चुअल विधि के लिए एक विधि सूचक पढ़ने के समान है।

फिर पढ़ने के मूल्य को केवल कास्ट के अपेक्षित स्थैतिक प्रकार की तुलना की आवश्यकता होती है। निर्देश सेट आर्किटेक्चर के आधार पर, किसी अन्य निर्देश को गलत शाखा पर शाखा (या गलती) की आवश्यकता होगी। 32-बिट एआरएम जैसे आईएसए में सशर्त निर्देश हैं और वे खुश रास्ते से दुखी मार्ग पारित करने में सक्षम हो सकते हैं।

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

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

+1

दिलचस्प - तो इसका मतलब यह है कि गैर-इंटरफ़ेस कक्षाओं के लिए यदि मैं सुपरक्लास एससी = (सुपरक्लास) सबक्लास लिखता हूं; कि (जिट यानी: लोड टाइम) कंपाइलर "क्लासिक" प्रत्येक सुपर क्लास और सबक्लास में ऑब्जेक्ट से ऑफ़सेट में "क्लास" हेडर में रखेगा और फिर एक साधारण ऐड + तुलना के माध्यम से चीजों को हल करने में सक्षम होगा? - यह अच्छा और तेज़ है :) इंटरफेस के लिए मैं एक छोटे हैशटेबल या ब्रीटी से भी बदतर नहीं मानूंगा? – peterk

+0

@peterk कक्षाओं के बीच कास्टिंग के लिए, ऑब्जेक्ट एड्रेस और "vtbl" (विधि पॉइंटर्स की तालिका, साथ ही श्रेणी पदानुक्रम की तालिका, इंटरफेस कैश इत्यादि) बदल नहीं है। तो [वर्ग] कास्ट इस प्रकार की जांच करता है, और यदि यह फिट बैठता है तो कुछ और नहीं होना चाहिए। –

1

सिद्धांत रूप में, ओवरहेड पेश किया गया है। हालांकि, आधुनिक जेवीएम स्मार्ट हैं। प्रत्येक कार्यान्वयन अलग है, लेकिन यह मानना ​​अनुचित नहीं है कि एक कार्यान्वयन मौजूद हो सकता है कि जेआईटी ने कास्टिंग चेक को ऑप्टिमाइज़ किया जब यह गारंटी दे सकता है कि कभी संघर्ष नहीं होगा। किस विशिष्ट जेवीएम के लिए यह पेशकश करता है, मैं आपको नहीं बता सका। मुझे स्वीकार करना होगा कि मैं खुद को जेआईटी अनुकूलन के विनिर्देशों को जानना चाहता हूं, लेकिन ये चिंता करने के लिए जेवीएम इंजीनियरों के लिए हैं।

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

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