Σύγκριση Java και C++ Μεταπτυχιακό Εφαρμοσμένης Πληροφορικής - Αλέξανδρος Χατζηγεωργίου, Νοέμβριος 2004
Διαφορές C++ - Java Η Java δημιουργήθηκε αρκετά αργότερα από την C++ και στηρίχθηκε σε μεγάλο βαθμό επάνω σε αυτήν. Για το λόγο αυτό το συντακτικό είναι σχεδόν παρόμοιο. Ωστόσο υπάρχει εντυπωσιακά μεγάλος αριθμός διαφορών μεταξύ της C++ και της Java Η σύγκριση που ακολουθεί παρουσιάζει τις (περισσότερες) διαφορές ως σημαντικές βελτιώσεις της Java έναντι της C++
Συγκριτική μελέτη C++ - Java 1. Η εμφανέστερη διαφορά είναι η ταχύτητα: Η Java που υφίσταται διερμηνεία (interpretation) καταλήγει να είναι περίπου 20 φορές πιο αργή από τη C. Ωστόσο τίποτα δεν εμποδίζει την κατασκευή μεταγλωττιστών για την Java (just-in-time compilers) 2. Στην Java οτιδήποτε πρέπει να βρίσκεται μέσα σε μία κλάση. Δεν υπάρχουν καθολικές συναρτήσεις ή καθολικές μεταβλητές. Αν χρειάζεται το ισοδύναμο των καθολικών, χρησιμοποιούνται static μέθοδοι ή δεδομένα μέσα σε μία κλάση. Δεν υπάρχουν επίσης structs ή enumerations ή unions (enumerations υπάρχουν στη Java 1.5)
Συγκριτική μελέτη C++ - Java 3. Όλες οι μέθοδοι ορίζονται (definitions) μέσα στο σώμα της κλάσης. Επομένως, αυτό θα φαινόταν στη C++ με το να δηλώσουμε όλες τις συναρτήσεις ως inline (αλλά δεν είναι). (Στη C++ μία member function που ορίζεται εξ'ολοκλήρου μέσα στην κλάση θεωρείται inline) 4. Οι ορισμοί των κλάσεων είναι περίπου ίδιοι για την Java και τη C++, αλλά στην Java δεν υπάρχει ελληνικό ερωτηματικό στο τέλος. Δεν υπάρχουν “δηλώσεις κλάσεων”, μόνο ορισμοί κλάσεων. 5. Δεν υπάρχει τελεστής εμβέλειας :: (scope resolution operator) στην Java. H Java χρησιμοποιεί τον τελεστή. για τα πάντα. Π.χ. C++ ClassName::staticMethod() αναφορά σε static μέλος Java ClassName.staticMethod() αναφορά σε static μέλος
Συγκριτική μελέτη C++ - Java 6. Η Java έχει όπως και η C++ ορισμένους στοιχειώδεις τύπους. Στην Java είναι οι: boolean, char, byte, short, int, long, float, double. Το μέγεθος των τύπων αυτών είναι καθορισμένο και ανεξάρτητο από την πλατφόρμα (έχει αρνητική επίπτωση στην ταχύτητα) Ο έλεγχος τύπων (type-checking) είναι πιο "σφιχτός" στην Java. Για παράδειγμα, στην Java δεν μπορώ να έχω παραστάσεις που λειτουργούν ως συνθήκες ελέγχου και δεν είναι boolean. Π.χ. if ( 5 + 3) System.out.println("This CANNOT BE DONE!!");
Συγκριτική μελέτη C++ - Java 7. Ο τύπος char στη Java χρησιμοποιεί το σύνολο χαρακτήρων 16-bit Unicode και κατά συνέπεια αναπαριστά τους περισσότερους εθνικούς χαρακτήρες αυτομάτως. 8. Αλφαριθμητικά μέσα σε " " μετατρέπονται αυτομάτως σε αντικείμενα τύπου String. Στην C τα αλφαριθμητικά δεν είναι αντικείμενα και έχουμε το εξής "πρόβλημα": char text[] = "This is a text"; text[3] = 'e';//Απολύτως επιτρεπτό char *p = "Hello there"; *(p+3) = 'e';//Απροσδιόριστο αποτέλεσμα string Ευτυχώς στην standard C++ library υπάρχει η κλάση string
Συγκριτική μελέτη C++ - Java 9. Παρόλο που φαίνονται παρόμοιοι, οι πίνακες στη Java έχουν διαφορετική δομή και συμπεριφορά από ότι στη C++. Υπάρχει μέλος δεδομένων (read-only) length που επιστρέφει το μέγεθος και run-time checking παράγει εξαίρεση αν "βγούμε" εκτός ορίων. Οι πίνακες δημιουργούνται πάντοτε στο σωρό (heap) Μπορεί να ανατεθεί ένας πίνακας σε έναν άλλο (array handle is copied). Αντίθετα στη C/C++ οι δηλώσεις και η εντολή: int A[3] = {2,3,1}; int B[3] = {3,4,5}; Α = Β; παράγουν σφάλμα '=' : left operand must be l-value
Συγκριτική μελέτη C++ - Java 10. Όλα τα αντικείμενα μη στοιχειωδών τύπων δημιουργούνται μόνο μέσω της δεσμευμένης λέξης new (στο σωρό - heap). (Στη C++ υπάρχει η δυνατότητα δημιουργίας μη στοιχειωδών τύπων στη στοίβα - stack). #include class Circle { public: void setRadius(int r); private: int radius; }; void Circle::setRadius(int r) { radius = r; } int main() { Circle myCircle;// myCircle created on the stack int x; scanf("%d", &x);// myCircle exists at this point myCircle.setRadius(x); return 0; }
Συγκριτική μελέτη C++ - Java ενώ αν στη C++ δημιουργηθεί ένα αντικείμενο στο σωρό με τον new: #include class Circle { public: void setRadius(int r); private: int radius; }; void Circle::setRadius(int r) { radius = r; } int main() { int x; scanf("%d", &x); Circle *myCircle = new Circle(); // Circle created on the heap (*myCircle).setRadius(x); return 0; }
Συγκριτική μελέτη C++ - Java 11. Δεν χρειάζεται στη Java να έχει δηλωθεί κάτι προτού χρησιμοποιηθεί (και συνεπώς δεν χρειάζονται και forward class declarations). Αν θέλετε να χρησιμοποιήσετε μία κλάση ή μία μέθοδο προτού αυτή οριστεί, απλώς τη χρησιμοποιείτε. Ο μεταγλωττιστής θα βρεί τον ορισμό (ακόμα και αν υπάρχει σε άλλο αρχείο). 12. Η Java δεν έχει preprocessor. Αν θέλετε να χρησιμοποιήσετε κλάσεις μίας βιβλιοθήκης, χρησιμοποιείτε import και το όνομα της βιβλιοθήκης.
Συγκριτική μελέτη C++ - Java 13. Αναφορές σε αντικείμενα που είναι μέλη κλάσεων αρχικοποιούνται αυτόματα σε null. Η αρχικοποίηση στοιχειωδών τύπων δεδομένων είναι εγγυημένη στη Java. 14. Δεν υπάρχουν pointers στη Java με την έννοια της C/C++. Κατά τη δημιουργία ενός αντικειμένου επιστρέφεται πάντοτε μία αναφορά. (Οι αναφορές (reference type) στη C++ δεν είναι το ίδιο: Πρέπει να αρχικοποιηθούν κατά τη δημιουργία τους και δεν μπορούν να "δείχνουν" αλλού στην πορεία). Π.χ. στη C++: int &count //count is a reference to an int αλλά πρέπει πάντα να αρχικοποιούνται: int count = 1; int &cRef = count; ++cRef; //increments count (can also be passed as reference) Στη C++ οι pointers μπορούν να δείχνουν οπουδήποτε στη μνήμη πράγμα επικίνδυνο. Στην Java δεν υπάρχει αριθμητική δεικτών.
Συγκριτική μελέτη C++ - Java 15. Δεν υπάρχει εντολή goto στην Java. Ο μόνος μηχανισμός άλματος χωρίς συνθήκη είναι η εντολή break label 16. H Java δεν έχει templates ή κάποια άλλη υλοποίηση παραμετροποιήσιμων τύπων. Υπάρχει ένα set συλλογών: Vector, Stack και Hashtable που λαμβάνουν αναφορές Object αλλά οι συλλογές αυτές δεν είναι σχεδιασμένες με βάση την απόδοση όπως η C++ Standard Template Library. (Στην Java 1.5 υπάρχουν generics, επιτρέπεται δηλαδή η δήλωση δομών όπου καθορίζεται ο τύπος των στοιχείων της χωρίς να χρειάζεται casting για την προσπέλαση ενός στοιχείου)
Συγκριτική μελέτη C++ - Java 16. H Java κάνει αυτόματη περισυλλογή αχρησιμοποίητου χώρου μνήμης και αποδέσμευση του (garbage collector – automatic memory management). Στην Java όλα τα αντικείμενα συλλέγονται από τον garbage collector όταν δοθεί η αναφορά null σε όλες τις αναφορές του αντικειμένου. public int GarMethod() { String s = new String("Test String"); System.out.println(s"); s = null; } Το αντικείμενο s θα συλλεχθεί, ωστόσο δεν είναι γνωστό το πότε. Στη C++ πρέπει να καταμετρώνται όλες οι αναφορές (pointers) με τιμή null και ο καθαρισμός του χώρου μνήμης πρέπει να γίνεται ρητά με την εντολή delete Ωστόσο τα memory leaks ενώ είναι δύσκολα στην Java, δεν είναι αδύνατα.
Συγκριτική μελέτη C++ - Java 17. H Java έχει ενσωματωμένη υποστήριξη για multithreading. Η κλάση Thread επιτρέπει τη δημιουργία νέων νημάτων (επικαλύπτοντας την run() μέθοδο). 18. Τα προσδιοριστικά ορατότητας (public, private, protected) δεν εφαρμόζονται στην Java σε μπλοκ κώδικα. Κάθε δήλωση μέλους μιας κλάσης λαμβάνει το δικό της προσδιοριστικό. (Αν δεν υπάρχει προσδιοριστικό τα μέλη είναι προσπελάσιμα στο ίδιο πακέτο). 19. Ένα αντικείμενο εσωτερικής (inner) κλάσης στη Java διατηρεί αναφορά προς το "περιβάλλον" αντικείμενο και μπορεί να προσπελάσει τα μέλη της εξωτερικής κλάσης σαν να ήταν δικά του. (Στη C++ χρειάζεται προσοχή ο έλεγχος πρόσβασης: Στο πρότυπο 2003 της C++ η εσωτερική κλάση έχει ειδικά δικαιώματα πρόσβασης στα μέλη της περικλείουσας κλάσης. Στο πρότυπο 1998 αντίθετα η εσωτερική κλάση δεν έχει ειδικά δικαιώματα πρόσβασης στην περικλείουσα κλάση)
Συγκριτική μελέτη C++ - Java 20. Στην Java χρησιμοποιείται η δεσμευμένη λέξη extends για την κληρονομικότητα και η super για τον καθορισμό μεθόδων που θα κληθούν από την γονική κλάση. (μόνο όμως μεθόδων που βρίσκονται ένα επίπεδο πιο πάνω). public class Foo extends Bar { public Foo(String msg) { super(msg);//Calls base constructor } public void baz(int i) {// Override super.baz(i);// Calls base method }
Συγκριτική μελέτη C++ - Java 21. Η Java παρέχει τη δυνατότητα διασυνδέσεων μέσω της δεσμευμένης λέξης interface ως ισοδύναμο μιας αφηρημένης κλάσης βάσης. public interface Face { public void smile(); } public class Baz extends Bar implements Face { public void smile() { System.out.println("A warm smile"); }
Συγκριτική μελέτη C++ - Java 22. Στην Java δεν υπάρχει η αναγκαιότητα της δεσμευμένης λέξης virtual καθώς σε όλες τις κλήσεις μη-στατικών μεθόδων χρησιμοποιείται δυναμική διασύνδεση. Στη C++ η δυνατότητα αυτή υπάρχει για λόγους απόδοσης: ("Αν δεν τη χρησιμοποιείς, μην πληρώνεις για αυτήν" - τη δυναμική διασύνδεση) Έστω το πρόγραμμα:
#include using namespace std; class Person { public: Person(string text); void print(); protected: string name; }; Person::Person(string text) { name = text; } void Person::print() { cout << "My name is: " << name << endl; } class Student:public Person { public: Student(string text, string dep); void print(); private: string school; }; Student::Student(string text, string dep) : Person(text) { school = dep; } void Student::print() { cout << "My name is: " << name << "and my school is: " << school << endl; }
int main() { Person *aPerson; Student *aStudent; Person P1("Takis"); aPerson = &P1; aPerson->print(); Student S1("Babis", "Harvard"); aStudent = &S1; aStudent->print(); //στατική διασύνδεση, όχι πολυμορφισμός return 0; } int main() { Person *aPerson; Person P1("Takis"); aPerson = &P1; aPerson->print(); Student S1("Babis", "Harvard"); aPerson = &S1; aPerson->print();//προσπάθεια για πολυμορφισμό, δεν δουλεύει //γιατί λείπει το virtual return 0; }
class Person { public: Person(string text); virtual void print();//ΠΡΟΣΟΧΗ protected: string name; }; int main() { Person *aPerson; Person P1("Takis"); aPerson = &P1; aPerson->print(); Student S1("Babis", "Harvard"); aPerson = &S1; aPerson->print();//ΠΟΛΥΜΟΡΦΙΣΜΟΣ, δυναμική διασύνδεση!! return 0; }
Συγκριτική μελέτη C++ - Java 23. Η Java δεν υποστηρίζει πολλαπλή κληρονομικότητα. Υλοποίηση πολλαπλών διασυνδέσεων ωστόσο επιτρέπεται. - - >