2009-07-27 18 views
5

यह एक प्रश्न है जो ज्यादातर शुद्ध जिज्ञासा (और कुछ समय मार रहा है) उत्पन्न हुआ। मैं विशेष रूप से कंक्रीटनेस के लिए जावा के बारे में पूछ रहा हूं।जावा में खाली स्ट्रिंग को संयोजित करते समय संकलन और रनटाइम पर क्या होता है?

अगर मैं कोई रिक्त स्ट्रिंग के साथ एक स्ट्रिंग (कोई भी स्ट्रिंग) को श्रेणीबद्ध स्मृति में, क्या होता है, उदाहरण के लिए:

String s = "any old string"; 
s += ""; 

मुझे पता है कि बाद में, रों की सामग्री को अभी भी "किसी भी पुराने स्ट्रिंग" हो जाएगा चूंकि एक खाली ASCII स्ट्रिंग को स्मृति में केवल एक ASCII शून्य के रूप में संग्रहीत किया जाता है (चूंकि, कम से कम जावा में, तार हमेशा शून्य-समाप्त होते हैं)। लेकिन मुझे यह जानकर उत्सुकता है कि क्या जावा (कंपाइलर? वीएम?) पर्याप्त अनुकूलन करता है यह जानने के लिए कि यह अपरिवर्तित होगा, और यह केवल उस निर्देश को बाइटकोड में छोड़ सकता है, या अगर संकलन और रन टाइम पर कुछ अलग होता है।

उत्तर

16

यह बाइटकोड समय है!

class EmptyString { 
    public static void main(String[] args) { 
     String s = "any old string"; 
     s += ""; 
    } 
} 

javap -c EmptyString:

 
Compiled from "EmptyString.java" 
class EmptyString extends java.lang.Object{ 
EmptyString(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String any old string 
    2: astore_1 
    3: new  #3; //class java/lang/StringBuilder 
    6: dup 
    7: invokespecial #4; //Method java/lang/StringBuilder."":()V 
    10: aload_1 
    11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    14: ldc  #6; //String 
    16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    22: astore_1 
    23: return 

} 

आप देख सकते हैं += का कारण बनता है कि एक StringBuilder यह क्या श्रृंखलाबद्ध है पर ध्यान दिए बिना बनाया जाना है, इसलिए यह रनटाइम पर अनुकूलित नहीं किया जा सकता है।

दूसरी ओर, यदि आप एक ही अभिव्यक्ति में दोनों स्ट्रिंग शाब्दिक डाल दिया, वे संकलक द्वारा concatenated रहे हैं:

class EmptyString { 
    public static void main(String[] args) { 
     String s = "any old string" + ""; 
    } 
} 

javap -c EmptyString:

 
Compiled from "EmptyString.java" 
class EmptyString extends java.lang.Object{ 
EmptyString(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String any old string 
    2: astore_1 
    3: return 

} 
+3

+1 - greatjustice – Alex

+0

शांत के लिए । धन्यवाद! –

+1

@mmyers: आपको यह इंगित करना चाहिए कि 1) उत्सर्जित बाइटकोड (सिद्धांत में) जावा कंपाइलर विशिष्ट हैं, और 2) जेआईटी कंपाइलर (सिद्धांत में) आगे अनुकूलित कर सकता है। –

2

आप लाइन

s += ""; 

जावा एक नया स्ट्रिंग ऑब्जेक्ट आवंटित और रों स्ट्रिंग संयोजन के बाद करने के लिए इसे प्रदान करती है को क्रियान्वित करने के बाद एक नया स्ट्रिंग मिल जाएगा। यदि आपके पास ग्रहण आसान है (और मुझे लगता है कि आप नेटबीन में भी वही काम कर सकते हैं, लेकिन मैंने कभी ग्रहण किया है) तो आप उस रेखा को तोड़ सकते हैं और उस ऑब्जेक्ट की ऑब्जेक्ट आईडी देख सकते हैं जो s निष्पादन से पहले और बाद में इंगित करता है वह रेखा मेरे मामले में, कोड की उस पंक्ति से पहले s की ऑब्जेक्ट आईडी आईडी = 20 थी, और बाद में आईडी = 24 थी।

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