1) इंटरनेट पर और StackOverflow पर जेनेरिक और varargs के साथ विशेष मुद्दे के बारे में कई उदाहरण हैं। मूल रूप से, यह तब होता है जब आपके पास एक टाइप-पैरामीटर प्रकार के तर्कों की चर संख्या होती है:
<T> void foo(T... args);
जावा में, varargs एक संश्लिष्ट चीनी है जो संकलन-समय पर एक सरल "री-राइटिंग" से गुजरता है: प्रकार X...
का एक varargs पैरामीटर एक प्रकार के पैरामीटर में परिवर्तित होता है X[]
; और हर बार जब इस वैरगेज विधि के लिए कॉल किया जाता है, तो कंपाइलर "वैरिएबल तर्क" के सभी को इकट्ठा करता है, जो वैरैगस पैरामीटर में जाता है, और एक सरणी बनाता है जैसे new X[] { ...(arguments go here)... }
।
यह अच्छी तरह से काम करता है जब varargs प्रकार ठोस होता है String...
। जब यह एक प्रकार का चर होता है T...
, तो यह T
उस कॉल के लिए एक ठोस प्रकार ज्ञात होने पर भी काम करता है। जैसे यदि विधि के ऊपर एक वर्ग का हिस्सा थे Foo<T>
, और आप एक है Foo<String>
संदर्भ है, तो बुला foo
पर यह क्योंकि हम जानते हैं उचित रहेगा T
है String
कोड में उस बिंदु पर।
हालांकि, यह तब काम नहीं करता है जब "मान" T
दूसरे प्रकार का पैरामीटर है। जावा में, प्रकार-पैरामीटर घटक प्रकार ( new T[] { ... }
) की एक सरणी बनाना असंभव है । इसलिए जावा इसके बजाय उपयोग करता है new Object[] { ... }
(यहां Object
ऊपरी सीमा है T
; यदि ऊपरी सीमा कुछ अलग थी, तो वह इसके बजाय होगी Object
), और फिर आपको एक संकलक चेतावनी देता है।
तो क्या या बनाने के new Object[]
बजाय क्या गलत है new T[]
? खैर, जावा में सरणियाँ उनके घटक प्रकार को रनटाइम पर जानते हैं। इस प्रकार, पारित सरणी वस्तु में रनटाइम पर गलत घटक प्रकार होगा।
केवल तत्वों पर पुनरावृति करने के लिए, शायद सबसे अधिक उपयोग किया जाने वाला वेरिएग, यह कोई समस्या नहीं है (आप क्रम के प्रकार के बारे में परवाह नहीं करते हैं), इसलिए यह सुरक्षित है:
@SafeVarargs
final <T> 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");
}
}
यहां समस्या यह है कि हम इसे वापस करने के लिए किस प्रकार के args
होने पर निर्भर हैं । लेकिन वास्तव में रनटाइम पर तर्क का प्रकार इसका उदाहरण नहीं है ।T[]
T[]
T[]
3) यदि आपकी विधि में तर्क का प्रकार है T...
(जहाँ T किसी भी प्रकार का पैरामीटर है), तो:
- सुरक्षित: यदि आपका तरीका केवल इस तथ्य पर निर्भर करता है कि सरणी के तत्व किस प्रकार के हैं
T
- असुरक्षित: यदि यह इस तथ्य पर निर्भर करता है कि सरणी किसका उदाहरण है
T[]
सरणी के रनटाइम प्रकार पर निर्भर करने वाली चीजों में शामिल हैं: प्रकार के रूप में इसे वापस करना T[]
, इसे प्रकार के एक तर्क के रूप में पास करना T[]
, सरणी प्रकार का उपयोग करना .getClass()
, इसे ऐसे तरीकों से पारित करना जो सरणी के रनटाइम प्रकार पर निर्भर करते हैं, जैसे List.toArray()
और Arrays.copyOf()
, आदि।
2) मैंने ऊपर उल्लेख किया भेद आसानी से स्वचालित रूप से प्रतिष्ठित होने के लिए बहुत जटिल है।