2013-01-09 12 views
136

मैं हाल ही में जावा @SafeVarargs एनोटेशन में आया हूं। क्या जावा असुरक्षित में एक variadic समारोह में आता है के लिए Googling मुझे छोड़ दिया बल्कि उलझन में (? ढेर विषाक्तता प्रकार मिट?), तो मैं कुछ बातें जानना चाहते हैं:जावा सेफवार्गा एनोटेशन, क्या मानक या सर्वोत्तम अभ्यास मौजूद है?

  1. क्या एक variadic जावा समारोह में असुरक्षित बनाता है @ सेफवार्गा समझ (अधिमानतः गहराई से उदाहरण के रूप में समझाया गया है)?

  2. प्रोग्रामर के विवेकानुसार यह टिप्पणी क्यों छोड़ी गई है? क्या ऐसा कुछ नहीं है जिसे संकलक जांचने में सक्षम होना चाहिए?

  3. क्या कुछ मानक को यह सुनिश्चित करने के लिए पालन करना चाहिए कि उसका कार्य वास्तव में varags सुरक्षित है? यदि नहीं, तो यह सुनिश्चित करने के लिए सर्वोत्तम प्रथाएं क्या हैं?

+1

क्या आपने [जावाडॉक] (http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html) में उदाहरण (और स्पष्टीकरण) देखा है? – jlordo

+2

आपके तीसरे प्रश्न के लिए, एक अभ्यास हमेशा पहले तत्व और दूसरों के लिए होता है: 'myTethod को पुनः टाइप करें (Arg पहले, Arg ... अन्य) '। यदि आप 'पहले' निर्दिष्ट नहीं करते हैं, तो खाली सरणी की अनुमति है, और आपके पास एक ही नाम से एक ही विधि के साथ एक विधि हो सकती है, जिसमें कोई तर्क नहीं होता है, जिसका अर्थ है कि जेवीएम को यह निर्धारित करने में कठिनाई होगी कि कौन सी विधि होनी चाहिए बुलाया। – fge

+4

@jlordo मैंने किया, लेकिन मुझे समझ में नहीं आ रहा है कि यह varargs संदर्भ में क्यों दिया गया है, क्योंकि यह इस स्थिति को एक varargs फ़ंक्शन के बाहर आसानी से समाप्त कर सकता है (सत्यापित किया गया है, अपेक्षित प्रकार की सुरक्षा चेतावनियों और रनटाइम पर त्रुटियों के साथ संकलित) .. – Oren

उत्तर

189

1) इंटरनेट पर और जेकिक्स और varargs के साथ विशेष मुद्दे के बारे में StackOverflow पर कई उदाहरण हैं। असल में, यह आप एक प्रकार पैरामीटर प्रकार के तर्कों के परिवर्तनशील है जब है:

void foo(T... args); 

जावा में, varargs एक वाक्यात्मक चीनी कि संकलन समय पर एक सरल "फिर से लेखन" से होकर गुजरती है कर रहे हैं: एक varargs पैरामीटर X... प्रकार X[] के पैरामीटर में परिवर्तित किया गया है; और हर बार इस varargs विधि के लिए एक कॉल किया जाता है, संकलक varargs पैरामीटर में चला जाता है कि सभी "परिवर्तनीय तर्क" एकत्र करता है, और new X[] { ...(arguments go here)... } की तरह एक सरणी बनाता है।

यह तब काम करता है जब varargs प्रकार String... जैसा ठोस होता है। जब यह एक प्रकार परिवर्तनीय है जैसे T..., यह तब भी काम करता है जब T उस कॉल के लिए ठोस प्रकार के रूप में जाना जाता है। जैसे यदि उपर्युक्त विधि Foo<T> वर्ग का हिस्सा थी, और आपके पास Foo<String> संदर्भ है, तो foo पर कॉल करना ठीक होगा क्योंकि हम जानते हैं कि TString कोड में उस बिंदु पर है।

हालांकि, यह काम नहीं करता है जब T का "मान" एक और प्रकार पैरामीटर है। जावा में, टाइप-पैरामीटर घटक प्रकार (new T[] { ... }) की सरणी बनाना असंभव है। तो जावा new Object[] { ... } का उपयोग करता है (यहां ObjectT की ऊपरी सीमा है; यदि ऊपरी सीमा कुछ अलग थी, तो यह Object के बजाय होगा, और फिर आपको एक कंपाइलर चेतावनी देता है।

तो new T[] के बजाय new Object[] बनाने के साथ क्या गलत है? खैर, जावा में सरणी रनटाइम पर उनके घटक प्रकार को जानते हैं। इस प्रकार, पास किए गए सरणी ऑब्जेक्ट में रनटाइम पर गलत घटक प्रकार होगा।

शायद varargs का सबसे आम उपयोग के लिए, बस तत्वों से अधिक पुनरावृति करने के लिए, यह कोई समस्या (आप सरणी के क्रम प्रकार के बारे में परवाह नहीं है) है, इसलिए इस सुरक्षित है:

@SafeVarargs 
final void foo(T... args) { 
    for (T x : args) { 
     // do stuff with x 
    } 
} 

हालांकि, किसी भी चीज के लिए जो पारित सरणी के रनटाइम घटक प्रकार पर निर्भर करता है, यह सुरक्षित नहीं होगा।

class UnSafeVarargs 
{ 
    static <T> T[] asArray(T... args) { 
    return args; 
    } 

    static <T> T[] arrayOfTwo(T a, T b) { 
    return asArray(a, b); 
    } 

    public static void main(String[] args) { 
    String[] bar = arrayOfTwo("hi", "mom"); 
    } 
} 

समस्या यहाँ है कि हम आदेश T[] के रूप में यह वापस जाने के लिए में T[] होने की args के प्रकार पर निर्भर है: यहाँ कुछ है कि असुरक्षित है और दुर्घटनाओं का एक सरल उदाहरण है। लेकिन वास्तव में रनटाइम पर तर्क का प्रकार T[] का उदाहरण नहीं है।

3) अपने विधि प्रकार T... (जहां टी किसी भी प्रकार के पैरामीटर है की एक तर्क है), तो:

  • सुरक्षित: अपने विधि केवल तथ्य पर निर्भर करता है कि सरणी के तत्वों के उदाहरण हैं T
  • असुरक्षित की: प्रकारके रूप में यह लौटने: यह तथ्य यह है कि सरणी T[]

चीज़ें है कि सरणी के क्रम प्रकार पर निर्भर शामिल का एक उदाहरण है पर निर्भर करता है, प्रकार T[] की एक पैरामीटर के लिए एक तर्क के रूप में यह पारित, .getClass() का उपयोग कर सरणी प्रकार हो रही है यह तरीकों कि सरणी, List.toArray() और Arrays.copyOf() तरह के रनटाइम प्रकार पर निर्भर करने के लिए पारित करने, आदि

2) भेद मैंने ऊपर वर्णित किया है कि स्वचालित रूप से आसानी से विशिष्ट होने के लिए बहुत जटिल है।

+4

अच्छी तरह से नाउ इट आल मेक्स सेंस। धन्यवाद। तो बस यह देखने के लिए कि मैं आपको पूरी तरह से समझता हूं, मान लीजिए कि हमारे पास एक वर्ग है 'FOO Oren

+4

@Oren: यह – newacct

+15

होना चाहिए यह ध्यान देने योग्य हो सकता है कि एक मामला जहां यह संभवतः (@ सुरक्षितवर्ग 'का उपयोग करने के लिए सही है (संभवतः) सरणी के साथ एकमात्र चीज है, यह किसी अन्य विधि को पास कर देती है जो पहले से ही एनोटेटेड है (उदाहरण के लिए: मैं अक्सर अपने आप को 'Arrays.asList (...)' का उपयोग करके अपनी तर्क को एक सूची में बदलने के लिए मौजूद vararg विधियों को लिखता हूं और इसे किसी अन्य विधि में पास करता हूं; ऐसे मामले को हमेशा @ @ सेफवार्गास 'के साथ एनोटेट किया जा सकता है। क्योंकि 'Arrays.asList' एनोटेशन है)। – Jules

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