क्या जावा कास्टिंग ओवरहेड का परिचय देता है? क्यों?


104

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

क्या यह एक सामान्य बात है, या अलग-अलग मामले हैं?

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

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

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


इंस्टाॅफ और कास्टिंग का प्रदर्शन काफी अच्छा है। मैंने जावा 7 में कुछ समय यहां समस्या के विभिन्न तरीकों के बारे में पोस्ट किया: stackoverflow.com/questions/16320014/…
व्हीज़िल

इस अन्य प्रश्न के बहुत अच्छे उत्तर हैं stackoverflow.com/questions/16741323/…
user454322

जवाबों:


78

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

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

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

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

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

इस दूसरे मामले में, रनटाइम में ओवरहेड है, क्योंकि दो प्रकारों की जांच होनी चाहिए और यदि कास्टिंग संभव नहीं है, तो JVM को क्लासकैस्ट अपवाद को फेंकना होगा।

JavaWorld से लिया गया : कास्टिंग की लागत

कास्टिंग का उपयोग प्रकारों के बीच परिवर्तित करने के लिए किया जाता है - विशेष रूप से संदर्भ प्रकारों के बीच, कास्टिंग ऑपरेशन के प्रकार के लिए जिसमें हम यहां रुचि रखते हैं।

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

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


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

1
@skaffman, वास्तव में मैं इसे नमक के एक दाने के साथ (कोई भी प्रदर्शन के बारे में परवाह किए बिना) करता हूं।
पचेरियर

क्या यह वही मामला होगा, अगर मैं संदर्भ के लिए कास्ट की गई वस्तु को असाइन नहीं करता हूं और इस पर सिर्फ कॉल विधि करता हूं? जैसे((String)o).someMethodOfCastedClass()
पार्थ विश्वजीत

3
अब लेख लगभग 20 साल पुराना है। और जवाब भी कई साल पुराने हैं। इस प्रश्न के लिए आधुनिक उत्तर की आवश्यकता है।
रसलानोव

कैसे आदिम प्रकार के बारे में? मेरा मतलब है, उदाहरण के लिए - int से लेकर शॉर्ट ओवरहेड समान कारण?
luke1985

44

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

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

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

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

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

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

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


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

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

8

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

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

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

कुछ जानकारी रन टाइम के आसपास रखी जाती है, लेकिन व्यक्तिगत तत्वों के स्थिर प्रकारों की नहीं। इसे आप क्लास फाइल फॉर्मेट को देखकर बता सकते हैं।

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

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


1
आदिम लोगों के बारे में क्या? (float) Math.toDegrees(theta)क्या यहां भी एक महत्वपूर्ण ओवरहेड होगा?
एसडी

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

6

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

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

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तब से मान्य है, जब तक ColoredPointकि प्वाइंट का उपवर्ग है, लेकिनpa[0] = new Point() यह मान्य नहीं है।

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

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


2

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

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.