जवाबों:
उनके बीच एक बड़ा अंतर है। C ++ में आपको सामान्य प्रकार के लिए एक वर्ग या एक इंटरफ़ेस निर्दिष्ट करने की आवश्यकता नहीं है। यही कारण है कि आप सही ढंग से सामान्य कार्यों और कक्षाएं बना सकते हैं, एक शिथिल टाइपिंग के कैवेट के साथ।
template <typename T> T sum(T a, T b) { return a + b; }
ऊपर दी गई विधि एक ही प्रकार की दो वस्तुओं को जोड़ती है, और इसका उपयोग किसी भी प्रकार T के लिए किया जा सकता है जिसमें "+" ऑपरेटर उपलब्ध है।
जावा में आपको एक प्रकार निर्दिष्ट करना होगा यदि आप पास की गई वस्तुओं पर विधियों को कॉल करना चाहते हैं, कुछ इस तरह से:
<T extends Something> T sum(T a, T b) { return a.add ( b ); }
C ++ में जेनेरिक फ़ंक्शंस / क्लासेस को केवल हेडर में परिभाषित किया जा सकता है, क्योंकि कंपाइलर विभिन्न प्रकारों के लिए अलग-अलग फ़ंक्शंस उत्पन्न करता है (जो कि इसके साथ लागू होता है)। तो संकलन धीमा है। जावा में संकलन में एक बड़ा जुर्माना नहीं है, लेकिन जावा "एरेसुरे" नामक एक तकनीक का उपयोग करता है जहां सामान्य प्रकार को रनटाइम पर मिटा दिया जाता है, इसलिए रनटाइम पर जावा वास्तव में कॉल कर रहा है ...
Something sum(Something a, Something b) { return a.add ( b ); }
जावा में इतनी सामान्य प्रोग्रामिंग वास्तव में उपयोगी नहीं है, यह केवल नए फ़ॉरेक्स निर्माण के साथ मदद करने के लिए थोड़ी सी सिन्सेटिक चीनी है।
EDIT: उपयोगिता पर ऊपर की राय एक छोटे स्वयं द्वारा लिखी गई थी। जावा के जेनेरिक पाठ्यक्रम की सुरक्षा के साथ मदद करते हैं।
extends
या तो के रूप में super
। उत्तर गलत है,
जावा जेनेरिक C ++ टेम्प्लेट में बड़े पैमाने पर भिन्न होते हैं ।
मूल रूप से C ++ टेम्प्लेट में मूल रूप से एक महिमामंडित प्रीप्रोसेसर / मैक्रो सेट होता है ( नोट: चूंकि कुछ लोग एक सादृश्य को समझने में असमर्थ हैं, मैं यह नहीं कह रहा हूं कि टेम्प्लेट प्रोसेसिंग एक मैक्रो है)। जावा में वे मूल रूप से सिंटैक्टिक शुगर हैं जो वस्तुओं के बॉयलरप्लेट कास्टिंग को कम करते हैं। यहाँ जावा जेनिक्स बनाम सी ++ टेम्पलेट्स के लिए एक बहुत ही अच्छा परिचय है ।
इस बिंदु पर विस्तार से बताने के लिए: जब आप C ++ टेम्पलेट का उपयोग करते हैं, तो आप मूल रूप से कोड की एक और प्रतिलिपि बना रहे हैं, जैसे कि आपने एक #define
मैक्रो का उपयोग किया हो । यह आपको int
टेम्प्लेट परिभाषाओं में पैरामीटर जैसी चीजें करने की अनुमति देता है जो एरे और इस तरह के आकार निर्धारित करते हैं।
जावा ऐसा काम नहीं करता है। जावा में सभी ऑब्जेक्ट्स java.lang.Object से सीमा तक हैं , पूर्व पीढ़ी के, आप इस तरह कोड लिखेंगे:
public class PhoneNumbers {
private Map phoneNumbers = new HashMap();
public String getPhoneNumber(String name) {
return (String)phoneNumbers.get(name);
}
...
}
क्योंकि सभी जावा संग्रह प्रकारों ने ऑब्जेक्ट को उनके आधार प्रकार के रूप में उपयोग किया है ताकि आप उनमें कुछ भी डाल सकें। जावा 5 चारों ओर घूमता है और जेनेरिक जोड़ता है ताकि आप निम्न चीजें कर सकें:
public class PhoneNumbers {
private Map<String, String> phoneNumbers = new HashMap<String, String>();
public String getPhoneNumber(String name) {
return phoneNumbers.get(name);
}
...
}
और यह सभी जावा जेनेरिक हैं: कास्टिंग ऑब्जेक्ट्स के लिए रैपर। ऐसा इसलिए है क्योंकि Java Generics को परिष्कृत नहीं किया गया है। वे प्रकार के क्षरण का उपयोग करते हैं। यह निर्णय इसलिए किया गया क्योंकि जावा जेनरिक उस टुकड़े में इतनी देरी से आया था कि वे पिछड़ी संगतता को तोड़ना नहीं चाहते थे ( Map<String, String>
जब भी Map
यह कहा जाता है तो यह प्रयोग करने योग्य है)। इसकी तुलना .Net / C # से करें जहां टाइप इरेज़र का उपयोग नहीं किया जाता है, जो सभी प्रकार के अंतर की ओर जाता है (जैसे कि आप आदिम प्रकारों का उपयोग कर सकते हैं IEnumerable
और IEnumerable<T>
एक दूसरे से कोई संबंध नहीं रख सकते हैं )।
और जावा 5+ संकलक के साथ संकलित जेनरिक का उपयोग करने वाला एक वर्ग JDK 1.4 पर प्रयोग करने योग्य है (यह मानते हुए कि जावा 5+ की आवश्यकता वाले अन्य सुविधाओं या वर्गों का उपयोग नहीं करता है)।
इसीलिए जावा जेनरिक को सिंटैक्टिक शुगर कहा जाता है ।
लेकिन जेनरिक कैसे करें इस निर्णय का गहरा प्रभाव इतना है कि जावा जेनरिक एफएक्यू एफएक्यू ने कई लोगों के जावा जेनरिक के बारे में कई सवालों के जवाब दिए हैं।
C ++ टेम्प्लेट में कई विशेषताएं होती हैं, जो Java Generics नहीं करती हैं:
आदिम प्रकार के तर्कों का उपयोग।
उदाहरण के लिए:
template<class T, int i>
class Matrix {
int T[i][i];
...
}
जावा जेनरिक में आदिम प्रकार के तर्कों के उपयोग की अनुमति नहीं देता है।
डिफ़ॉल्ट प्रकार के तर्कों का उपयोग , जो कि एक विशेषता है जो मुझे जावा में याद आती है, लेकिन इसके लिए पश्चगामी संगतता कारण हैं;
उदाहरण के लिए:
public class ObservableList<T extends List> {
...
}
यह वास्तव में जोर देने की आवश्यकता है कि विभिन्न तर्कों के साथ टेम्प्लेट इनवोकेशन वास्तव में अलग-अलग प्रकार के होते हैं। वे स्थैतिक सदस्यों को भी साझा नहीं करते हैं। जावा में ऐसा नहीं है।
संपूर्णता के लिए, जेनेरिक के साथ मतभेदों के अलावा, यहां C ++ और जावा (और एक अन्य ) की एक बुनियादी तुलना है ।
और मैं Java में Thinking का सुझाव भी दे सकता हूँ । C ++ प्रोग्रामर के रूप में बहुत सी अवधारणाएं ऑब्जेक्ट्स की तरह होंगी, जो पहले से ही दूसरी प्रकृति होगी लेकिन सूक्ष्म अंतर हैं इसलिए यह एक परिचयात्मक पाठ के लिए सार्थक हो सकता है भले ही आप भागों को स्किम करते हों।
जावा सीखते समय आप जो कुछ भी सीखेंगे, वह सभी पुस्तकालयों (दोनों मानक - जेडीके में आता है - और गैर-मानक है, जिसमें आमतौर पर स्प्रिंग जैसी चीजें शामिल हैं)। जावा सिंटैक्स C ++ सिंटैक्स की तुलना में अधिक क्रियाशील है और इसमें बहुत सी C ++ विशेषताएँ नहीं हैं (जैसे ऑपरेटर ओवरलोडिंग, मल्टीपल इनहेरिटेंस, डिस्ट्रॉक्टर मैकेनिज़्म आदि), लेकिन यह कड़ाई से इसे C ++ का सबसेट नहीं बनाता है।
Map map = new HashMap<String, String>
। इसका मतलब है कि आप एक पुराने JVM पर नए कोड को तैनात कर सकते हैं और यह bytecode में समानता के कारण चलेगा।
C ++ में टेम्प्लेट हैं। जावा में जेनेरिक हैं, जो C ++ टेम्प्लेट की तरह थोड़े सॉर्ट करते हैं, लेकिन वे बहुत, बहुत अलग हैं।
टेम्पलेट काम करते हैं, जैसा कि नाम का तात्पर्य है, कंपाइलर को (इसके लिए प्रतीक्षा करें ...) टेम्प्लेट प्रदान करके, जिसका उपयोग वह टेम्प्लेट मापदंडों में भरकर टाइप-सेफ कोड जनरेट करने के लिए कर सकता है।
जेनरिक, जैसा कि मैं उन्हें समझता हूं, दूसरे तरीके से काम करते हैं: कंपाइलर द्वारा टाइप पैरामीटर का उपयोग यह सत्यापित करने के लिए किया जाता है कि उनका उपयोग करने वाला कोड टाइप-सुरक्षित है, लेकिन परिणामी कोड बिना किसी प्रकार के उत्पन्न होता है।
C ++ टेम्प्लेट को वास्तव में अच्छा मैक्रो सिस्टम के रूप में सोचें , और जावा जेनरिक स्वचालित रूप से टाइपकास्ट उत्पन्न करने के लिए एक उपकरण के रूप में।
const
। C ++ में किसी ऑब्जेक्ट को एक const
पॉइंटर के माध्यम से तब तक संशोधित नहीं किया जाएगा जब तक कि const
-नेस दूर नहीं डाली जाती। इसी तरह, जावा में जेनेरिक प्रकारों द्वारा बनाई गई निहित जातियों को "सुरक्षित" होने की गारंटी दी जाती है, जब तक कि प्रकार के पैरामीटर मैन्युअल रूप से कोड में कहीं दूर नहीं डाले जाते हैं।
C ++ टेम्प्लेट की एक और विशेषता यह है कि जावा जेनरिक विशेषज्ञता नहीं है। यह आपको विशिष्ट प्रकारों के लिए एक अलग कार्यान्वयन करने की अनुमति देता है। तो अगर आप कर सकते हैं, उदाहरण के लिए, एक के लिए एक उच्च अनुकूलित संस्करण है पूर्णांक , जबकि अभी भी प्रकार के बाकी के लिए एक सामान्य संस्करण है। या आपके पास पॉइंटर और नॉन-पॉइंटर प्रकार के लिए अलग-अलग संस्करण हो सकते हैं। यह तब काम आता है जब आप एक पॉइंटर सौंपने के बाद डीरिफर की गई वस्तु पर काम करना चाहते हैं।
जावा जेनेरिक एंड कलेक्शंस बाय मौरिस नेफ्टलिन, फिलिप वाडलर में इस विषय की बहुत व्याख्या है । इस पुस्तक की पुरजोर सिफारिश की जाती है। उद्धरण के लिए:
जावा में जेनेरिक, C ++ में टेम्पलेट से मिलते जुलते हैं। ... वाक्य-विन्यास जानबूझकर समान है और शब्दार्थ जानबूझकर अलग हैं। ... शब्दार्थ, जावा जेनरिक को एरेस्योर द्वारा परिभाषित किया गया है, जहां C ++ टेम्प्लेट विस्तार द्वारा परिभाषित किए गए हैं।
कृपया पूरा विवरण यहाँ पढ़ें ।
(स्रोत: अजवायन.कॉम )
मूल रूप से, AFAIK, C ++ टेम्प्लेट प्रत्येक प्रकार के लिए कोड की एक प्रति बनाते हैं, जबकि जावा जेनरिक बिल्कुल उसी कोड का उपयोग करते हैं।
हां, आप कह सकते हैं कि C ++ टेम्प्लेट जावा जेनेरिक कॉन्सेप्ट के बराबर है (हालांकि यह कहना ठीक होगा कि जावा जेनेरिक कॉन्सेप्ट में C ++ के बराबर हैं)
यदि आप C ++ के टेम्पलेट तंत्र से परिचित हैं, तो आप सोच सकते हैं कि जेनेरिक समान हैं, लेकिन समानता सतही है। जेनरिक प्रत्येक विशेषज्ञता के लिए एक नया वर्ग उत्पन्न नहीं करते हैं, न ही वे "टेम्पलेट मेटाप्रोग्रामिंग" की अनुमति देते हैं।
से: जावा पीढ़ी
जावा (और C #) जेनेरिक एक साधारण रन-टाइम प्रकार प्रतिस्थापन तंत्र प्रतीत होता है।
C ++ टेम्प्लेट एक संकलन-समय निर्माण है जो आपको अपनी आवश्यकताओं के अनुरूप भाषा को संशोधित करने का एक तरीका देता है। वे वास्तव में एक विशुद्ध रूप से कार्यात्मक भाषा हैं जो संकलक एक संकलन के दौरान निष्पादित करते हैं।
C ++ टेम्पलेट का एक और लाभ विशेषज्ञता है।
template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
Special sum(const Special& a, const Special& b) { return a.plus(b); }
अब, यदि आप बिंदुओं के साथ योग कहते हैं, तो दूसरी विधि को बुलाया जाएगा, यदि आप गैर-सूचक वस्तुओं के साथ योग कहते हैं, तो पहली विधि को बुलाया जाएगा, और यदि आप वस्तुओं के sum
साथ कॉल करते Special
हैं, तो तीसरा कहा जाएगा। मुझे नहीं लगता कि यह जावा के साथ संभव है।
मैं इसे एक वाक्य में सम्मिलित करूंगा: टेम्पलेट नए प्रकार बनाते हैं, जेनेरिक मौजूदा प्रकारों को प्रतिबंधित करता है।
@Keith:
यह कोड वास्तव में गलत है और इसके अलावा छोटे ग्लिट्स ( template
छोड़े गए, स्पेशलाइजेशन सिंटैक्स अलग तरह से दिखते हैं), आंशिक विशेषज्ञता फंक्शन टेम्प्लेट्स पर काम नहीं करती है, केवल क्लास टेम्प्लेट पर। कोड हालांकि, पुराने पुराने ओवरलोडिंग के बजाय आंशिक टेम्पलेट विशेषज्ञता के बिना काम करेगा:
template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
नीचे दिया गया जवाब क्रैकिंग द कोडिंग इंटरव्यू किताब से लिया गया है सॉल्यूशंस से अध्याय 13 , जो मुझे लगता है कि बहुत अच्छा है।
जावा जेनेरिक के कार्यान्वयन को "टाइप इरेज़र:" के विचार में निहित किया गया है। यह तकनीक पैरामीटर प्रकार को समाप्त कर देती है जब स्रोत कोड जावा वर्चुअल मशीन (जेवीएम) बाइटकोड में अनुवादित होता है। उदाहरण के लिए, मान लीजिए कि आपके पास नीचे जावा सॉफ्टवेयर है:
Vector<String> vector = new Vector<String>();
vector.add(new String("hello"));
String str = vector.get(0);
संकलन के दौरान, इस कोड को फिर से लिखा गया है:
Vector vector = new Vector();
vector.add(new String("hello"));
String str = (String) vector.get(0);
जावा जेनरिक का उपयोग वास्तव में हमारी क्षमताओं के बारे में ज्यादा नहीं बदला है; यह सिर्फ चीजों को थोड़ा चौकस कर देता है। इस कारण से, जावा जेनरिक को कभी-कभी "सिंटैक्टिक शुगर: 'कहा जाता है।
यह C ++ से काफी अलग है। C ++ में, टेम्पलेट अनिवार्य रूप से एक गौरवशाली मैक्रो सेट है, जिसमें कंपाइलर प्रत्येक प्रकार के लिए टेम्प्लेट कोड की एक नई प्रतिलिपि बनाता है। इस बात का प्रमाण इस तथ्य में है कि MyClass का एक उदाहरण स्थिर चर withMyClass को साझा नहीं करेगा। हालाँकि, MyClass के टाव इंस्टेंस एक स्थिर चर साझा करेंगे।
/*** MyClass.h ***/
template<class T> class MyClass {
public:
static int val;
MyClass(int v) { val v;}
};
/*** MyClass.cpp ***/
template<typename T>
int MyClass<T>::bar;
template class MyClass<Foo>;
template class MyClass<Bar>;
/*** main.cpp ***/
MyClass<Foo> * fool
MyClass<Foo> * foo2
MyClass<Bar> * barl
MyClass<Bar> * bar2
new MyClass<Foo>(10);
new MyClass<Foo>(15);
new MyClass<Bar>(20);
new MyClass<Bar>(35);
int fl fool->val; // will equal 15
int f2 foo2->val; // will equal 15
int bl barl->val; // will equal 35
int b2 bar2->val; // will equal 35
जावा में, स्थिर चर को MyClass के उदाहरणों में साझा किया जाता है, चाहे वह ff स्तंभ प्रकार के मापदंडों की परवाह किए बिना हो।
जावा जेनरिक और C ++ टेम्प्लेट में कई अन्य अंतर हैं। इसमें शामिल है:
टेम्पलेट एक मैक्रो सिस्टम के अलावा और कुछ नहीं है। सिंटेक्स शुगर। वे वास्तविक संकलन से पहले पूरी तरह से विस्तारित हैं (या, कम से कम, संकलक व्यवहार करते हैं जैसे कि मामला था)।
उदाहरण:
मान लीजिए कि हम दो कार्य चाहते हैं। एक फ़ंक्शन संख्याओं के दो अनुक्रम (सूची, सरणियाँ, वैक्टर, जो भी जाता है) लेता है और अपने आंतरिक उत्पाद को लौटाता है। एक अन्य फ़ंक्शन में एक लंबाई होती है, उस लंबाई के दो अनुक्रम उत्पन्न करता है, उन्हें पहले फ़ंक्शन में भेजता है, और परिणाम देता है। पकड़ यह है कि हम दूसरे फ़ंक्शन में गलती कर सकते हैं, ताकि ये दोनों कार्य वास्तव में एक ही लंबाई के न हों। हमें इस मामले में चेतावनी देने के लिए कंपाइलर की जरूरत है। नहीं जब कार्यक्रम चल रहा है, लेकिन जब यह संकलन है।
जावा में आप कुछ इस तरह से कर सकते हैं:
import java.io.*;
interface ScalarProduct<A> {
public Integer scalarProduct(A second);
}
class Nil implements ScalarProduct<Nil>{
Nil(){}
public Integer scalarProduct(Nil second) {
return 0;
}
}
class Cons<A implements ScalarProduct<A>> implements ScalarProduct<Cons<A>>{
public Integer value;
public A tail;
Cons(Integer _value, A _tail) {
value = _value;
tail = _tail;
}
public Integer scalarProduct(Cons<A> second){
return value * second.value + tail.scalarProduct(second.tail);
}
}
class _Test{
public static Integer main(Integer n){
return _main(n, 0, new Nil(), new Nil());
}
public static <A implements ScalarProduct<A>>
Integer _main(Integer n, Integer i, A first, A second){
if (n == 0) {
return first.scalarProduct(second);
} else {
return _main(n-1, i+1,
new Cons<A>(2*i+1,first), new Cons<A>(i*i, second));
//the following line won't compile, it produces an error:
//return _main(n-1, i+1, first, new Cons<A>(i*i, second));
}
}
}
public class Test{
public static void main(String [] args){
System.out.print("Enter a number: ");
try {
BufferedReader is =
new BufferedReader(new InputStreamReader(System.in));
String line = is.readLine();
Integer val = Integer.parseInt(line);
System.out.println(_Test.main(val));
} catch (NumberFormatException ex) {
System.err.println("Not a valid number");
} catch (IOException e) {
System.err.println("Unexpected IO ERROR");
}
}
}
C # में आप लगभग एक ही बात लिख सकते हैं। C ++ में इसे फिर से लिखने की कोशिश करें, और यह टेम्पलेट्स के अनंत विस्तार के बारे में शिकायत करते हुए, संकलन नहीं करेगा।
मैं यहाँ askanydifference का उद्धरण देना चाहूंगा :
सी ++ और जावा के बीच मुख्य अंतर प्लेटफॉर्म पर उनकी निर्भरता में निहित है। जबकि, C ++ प्लेटफॉर्म डिपेंडेंट लैंग्वेज है, जावा प्लेटफॉर्म इंडिपेंडेंट लैंग्वेज है।
उपरोक्त कथन यही कारण है कि C ++ सही सामान्य प्रकार प्रदान करने में सक्षम है। जबकि जावा की सख्त जाँच है और इसलिए वे जेनेरिक का उपयोग करने की अनुमति नहीं देते हैं जिस तरह से सी ++ इसकी अनुमति देता है।