Кіріспе

Екі бағдарламалау тілін салыстыру

Java және C++ екі көрнекті объектіге бағытталған бағдарламалау тілдері. Көптеген тілдердің танымалдылығын көрсететін өлшемдер бойынша, бұл екі тіл 21-ші ғасырдың көп бөлігінде объектіге бағытталған және жоғары өнімділікке ие бағдарламалық құралдарды жасауда үстемдік танытты және олар жиі салыстырылып, қарама-қайшы қойылады. Java синтаксисі C/C++ тілінің негізінде құрылған.

Жобалау мақсаттары

C++ және Java бағдарламалау тілдерінің айырмашылықтары олардың тарихына байланысты болуы мүмкін, себебі олардың жобалау мақсаттары әртүрлі. C++ жүйелік және қолданбалық бағдарламалауға (яғни, инфрақұрылымдық бағдарламалауға) арналған, бұл тиімді орындалу үшін жасалған C процедуралық бағдарламалау тілін кеңейтті. C-ге C++ объектіге бағдарланған бағдарламалауды, ерекше жағдайларды басқаруды, өмірлік циклға негізделген ресурстарды басқаруды (Resource Acquisition Is Initialization (RAII)), жалпылама бағдарламалауды, шаблондық метапрограммалауды және жалпы контейнерлер мен алгоритмдерді (Стандартты шаблондық кітапхана немесе STL) қамтитын C++ стандартты кітапханасын, сондай-ақ көптеген жалпы мақсаттағы мүмкіндіктерді қосты. Java – жалпы мақсаттағы, бір уақытта орындалатын, сыныпқа негізделген, объектіге бағдарланған бағдарламалау тілі, ол іске асыру тәуелділіктерін азайтуға арналған. Ол қауіпсіздік пен жоғары тасымалдау үшін Java виртуалды машинасына сенеді. Ол негізгі платформаның абстракциясын қамтамасыз ететін кең кітапханамен бірге келеді. Java – C++ синтаксисіне ұқсас (бірақ онымен үйлеспейтін) статикалық типтелген объектіге бағдарланған тіл. Оған Javadoc деп аталатын құжаттама жүйесі кіреді. C++ және Java-ны әзірлеудегі әртүрлі мақсаттар тілдер арасындағы әртүрлі принциптерге және жобалық таңдауларға әкелді. Айырмашылықтар мыналар:

C++ Java C тілін объектіге бағдарланған бағдарламалау және жалпылама бағдарламалаумен кеңейтеді. C кодын пайдалану орынды. C++/C синтаксисіне күшті әсер етеді. C бастапқы кодымен үйлесімді, кейбір ерекше жағдайларды қоспағанда. Java Native Interface және жақында Java Native Access C/C++ кодын тікелей шақыру үшін ұсынады. Дегенмен, туған тілдер қауіпсіз емес және туған тілдерді пайдаланатын қолданбалар жадтың бұзылуына ұшырауы мүмкін. Егер код мұқият жазылмаса, туған әдістер жүйенің өнімділігін төмендетуі мүмкін, себебі қоқыс жинаушы туған жадты пайдалануды бақылай алмайды немесе сақтай алмайды, ал туған және туған емес код арасында контексттік ауысуға шығын бар. Бір рет жазып, кез келген жерде компиляциялау (WOCA). Бір рет жазып, кез келген жерде/барлық жерде орындау (WORA/WORE). Процедуралық бағдарламалау, функционалдық бағдарламалау, объектіге бағдарланған бағдарламалау, жалпылама бағдарламалау және шаблондық метапрограммалауға мүмкіндік береді. Парадигмалардың қосылуын жақсы көреді. Процедуралық бағдарламалауға, функционалдық бағдарламалауға (Java 8 бастап) және жалпылама бағдарламалауға (Java 5 бастап) мүмкіндік береді, бірақ объектіге бағдарланған бағдарламалау парадигмасын қатты ұсынады. Скрипттеу тілдерін жасауға қолдау көрсетеді. Мақсатты нұсқаулар жиынтығы үшін туған машиналық код ретінде орындалады. Виртуалды машинада орындалады. Объекті типтерін және типтік атауларды ұсынады. Орындалу уақытындағы типтік ақпарат (RTTI) арқылы ойлануға мүмкіндік береді. Метапрограммалау және динамикалық кодты жасау кезінде ойлануға мүмкіндік береді. Көптеген екілік үйлесімділік стандарттары бар (әдетте Microsoft (MSVC компиляторы үшін) және Itanium/GNU (басқа барлық компиляторлар үшін)). Бір екілік үйлесімділік стандарты бар, операциялық жүйе және компилятор үшін платформааралық. Міндетті автоматты шекараны тексеру (мысалы, вектор және жол контейнерлеріндегі at әдісі). Java-ның барлық сәйкес дистрибутивтерінде барлық операциялар тексерілуі керек. HotSpot шекараны тексеруді алып тастауі мүмкін. Туған қолтаңбасыз арифметикалық қолдау. Туған қолтаңбасыз арифметика қолдау көрсетілмейді. Java 8 бұның бір бөлігін өзгертеді, бірақ аспектілері белгісіз. Барлық сандық типтер үшін стандартталған ең төменгі шектер, бірақ нақты өлшемдер іске асырылуына байланысты. Стандартталған типтер стандартты кітапхана арқылы қол жетімді. Барлық платформалардағы барлық примитивтік типтердің стандартталған шектері мен өлшемдері. Барлық типтерде (примитивтік немесе пайдаланушы анықтаған) көрсеткіштер, сілтемелер және мән бойынша өту қолдау көрсетіледі. Барлық типтер (примитивтік типтер және сілтеме типтері) әрқашан мән бойынша беріледі. Жадты басқару жаңа / өшіру арқылы қолмен, ауқымы бойынша автоматты түрде немесе ақылды сілтемелер арқылы жасалуы мүмкін. Объектілерді детерминистік жоюды қолдайды. Garbage collection ABI C++11-де стандартталған, бірақ компиляторлар garbage collection-ды іске асыруға міндетті емес. Автоматты қоқыс жинау. Детерминистік емес finalize әдісін қолдайды, оны пайдалану ұсынылмайды. Ресурстарды басқару қолмен немесе автоматты түрде өмірлік циклға негізделген ресурстарды басқару (RAII) арқылы жасалуы мүмкін. Ресурстарды басқару әдетте қолмен немесе финализаторлар арқылы автоматты түрде жасалуы керек, бірақ бұл әдетте ұсынылмайды. Автоматты өмірлік циклға негізделген ресурстарды басқару үшін try-with-resources бар (7-нұсқадан бастап). Оны sun.misc ішкі API-ін пайдаланып жасауға болады, бірақ бұл пайдалану қатаң түрде ұсынылмайды және болашақ Java нұсқасында жария API-імен алмастырылады. Сыныптарды, құрылымдарды (пассивті дерек құрылымдары (PDS) типтері) және біріктірулерді қолдайды және оларды қалыпқа келтіру немесе стекке орналастыруға болады. Сыныптар қалыпқа келтіруде орналасқан. Java SE 6 кейбір нысандарды стекке орналастыру үшін қашу талдауын оңтайландырады. Типтерді нақты түрде жобауға және C-мен үйлесімді болу үшін кейбір жасыратын түрлендірулерге мүмкіндік береді. Көбейту түрлендірулерінен басқа қатаң типтік қауіпсіздік. C++ стандартты кітапханасы шектеулі көлемге және функцияларға ие болу үшін жобаланған, бірақ тілдік қолдауды, диагностиканы, жалпы пайдалы құралдарды, жолдарды, жергілікті тілдерді, контейнерлерді, алгоритмдерді, итераторларды, сандық есептеулерді, кіріс-шығысты, кездейсоқ сандар генераторларын, тұрақты өрнектерді талдауды, жіптік мүмкіндіктерді, типтік қасиеттерді (статикалық типтік интроспекция үшін) және Стандартты C кітапханасын қамтиды. Boost кітапханасы желілік кіріс-шығыс сияқты қосымша функцияларды ұсынады. GUI және басқа функциялар үшін көптеген үшінші тарап кітапханалары бар: Adaptive Communication Environment (ACE), Crypto++, әртүрлі XMPP жедел хабар алмасу (IM) кітапханалары, OpenLDAP, Qt, gtkmm. Кітапхана әр шығарылыммен өсті. 1.6 нұсқасына қарай кітапхана жергілікті тілдерді, журналды жүргізуді, контейнерлерді және итераторларды, алгоритмдерді, GUI бағдарламалауды (бірақ жүйелік GUI-ды пайдаланбастан), графиканы, көп жіптік қолдауды, желіні, платформалық қауіпсіздікті, интроспекцияны, динамикалық сыныпты жүктеуді, тоқтатылмайтын және тоқтатылатын кіріс-шығысты қамтыды. XML, XSLT, MIDI, дерекқорға қосылу, атау қызметтері (мысалы, LDAP), криптография, қауіпсіздік қызметтері (мысалы, Kerberos), басып шығару қызметтері және веб-қызметтері үшін интерфейстер немесе қолдау сыныптарын ұсынды. SWT платформаға қатысты GUI-лар үшін абстракция ұсынды, бірақ соңғы шығарылымдарда JavaFX-пен алмастырылды; графикалық үдетуге және CSS тақырыптық интерфейстерге мүмкіндік берді. Бірақ ол ешқандай «туған платформалық көрініс» қолдауын қолдамайды. Көптеген операторлар үшін операторларды жүктеу. Мағынаны (семантиканы) сақтау ұсынылады. Операторларды жобау мүмкін емес. Тіл жол класы үшін + және += операторларын жобалайды. Сыныптардың жеке және көптеген мұрагерліктері, соның ішінде виртуалды мұрагерлік. Тек сыныптардың жеке мұрагерлігін қолдайды. Компиляция уақытындағы шаблондық түрлер. Толық Тьюрингті метапрограммалауға мүмкіндік береді. Жалпылама типтік параметрлеуді жүзеге асыру үшін жалпылама түрлер қолданылады, бірақ компилятордың типтік жоюын пайдалануға байланысты олар бастапқы кодтан байт-кодқа аударылмайды. Функциялық көрсеткіштер, функциялық нысандар, лямбдалар (C++11-де) және интерфейстер (абстракті сыныптарды пайдалану). Функциялық сілтемелер, функциялық нысандар және лямбдалар Java 8-де қосылды. Сыныптар (және интерфейстер, бұл сыныптар) SomeClass.class және someObject.getClass арқылы сілтемелер ретінде беріледі. Стандартты құжаттама механизмі жоқ. Үшінші тараптық бағдарламалық құралдар (мысалы, Doxygen) бар. Барлық жүйелік сыныптар мен әдістерде кең Javadoc құжаттама стандарты. Өзгертілмейтін айнымалыларды және нысанды өзгертетін мүшелік функцияларды анықтау үшін const кілт сөзі. Const-лық кодтың дұрыстығын өзгертпейтін нысандарға қатысты тексеру үшін компиляция уақытында күшпен сақталады (const дұрыстығын қараңыз). final нысандар үшін type* const көрсеткіштеріне балама const нұсқасын ұсынады және примитивтік типтер үшін const. Нысан мүшелерінің өзгертпейтін болуы оқылатын интерфейстер және нысанды капсулалау арқылы жүзеге асырылады. goto операторын қолдайды. Циклдармен және операторлық блоктармен бірге белгілерді қолдайды. goto Java спецификациясында «қолданылмаған» деп белгіленген резервтелген кілт сөз. Көзді код...

Семантика

C++ функциялардың/әдістердің аргументтері үшін әдепкі мәндерге рұқсат береді. Java-да мұндай мүмкіндік жоқ. Дегенмен, Java-да ұқсас нәтижелерді алу үшін әдіс жүктеуін қолдануға болады, бірақ бұл артық код тудырады. C++ үшін компиляциялау үшін қажетті кодтың ең аз бөлігі – функция, ал Java үшін – класс. C++ жергілікті типтер арасында кең ауқымды жасырын түрлендірулерді (кейбір қысқарту түрлендірулерін қоса алғанда) қолдайды, сондай-ақ пайдаланушы анықтаған типтерді қамтитын жасырын түрлендірулерді анықтауға мүмкіндік береді. Java-да жергілікті типтер арасында тек кеңейту түрлендірулері ғана жасырын түрде жүзеге асырылады; ал қалған түрлендірулерге ашық түрлендіру синтаксисі қажет. Осының салдарынан, Java және C++-дағы шарттық өрнектер (if, while және for циклындағы шығу шарты) boolean түрін күтсе де, if (a = 5) сияқты код Java-да компиляция қатесіне алып келеді, себебі int-тен boolean-ге жасырын түрлендіру жоқ, бірақ C++-да компиляцияланады. Егер код қате жазылған болса және if (a == 5) деп жазу мақсаты болған болса, бұл пайдалы болуы мүмкін. Алайда, қазіргі C++ компиляторлары мұндай тапсырма шарттық өрнекте орындалғанда ескерту жасайды. Сол сияқты, жанама әсері жоқ дербес салыстыру операторлары, мысалы a == 5;, көбінесе ескерту тудырады. Функцияларға параметрлерді беру үшін C++ сілтеме арқылы және мән арқылы беруді қолдайды. Java-да примитив параметрлер әрқашан мән арқылы беріледі. Класс, интерфейс және массив типтері Java-да бірлесіп сілтеме типтері деп аталады және олар да әрқашан мән арқылы беріледі. Java-дағы құрастырылған типтер тіл спецификациясымен анықталған белгілі бір мөлшерге және диапазондағы мәндерге ие. C++-да құрастырылған типтер үшін минималды диапазон анықталған, бірақ нақты бейнелеу (биттер саны) белгілі бір платформадағы артықшылықты білдіретін кез келген жергілікті типке сәйкестендірілуі мүмкін. Мысалы, Java символдары 16 биттік Unicode символдары болып табылады, ал жолдар осындай символдардың тізбегінен тұрады. C++ тар және кең символдарды ұсынады, бірақ олардың нақты мөлшері платформаға тәуелді, сондай-ақ қолданылатын символдар жиынтығы да. Жолдар екі типтен де құрастырылуы мүмкін. Бұл сонымен қатар C++ компиляторлары мақсатты платформа үшін ең тиімді бейнелеуді автоматты түрде таңдай алады (мысалы, 64 биттік платформа үшін 64 биттік бүтін сандар), ал Java-да бейнелеу бекітілген, яғни мәндер аз тиімді мөлшерде сақталуы мүмкін немесе қалған биттерді толтыру және азайтылған енді мінез-құлықты эмуляциялау үшін код қосу қажет. C++-тағы қозғалатын нүктелердің және операциялардың дөңгелектеуі мен дәлдігі жүзеге асырылуға байланысты анықталады (егер тек өте ерекше немесе ескі платформалар IEEE 754 стандартынан ауытқыса). Java платформалар бойынша біркелкі нәтижелерге кепілдік беретін, бірақ орындалу уақытының жылдамдығын төмендетуі мүмкін ерікті қатаң қозғалатын нүктелік модельді (strictfp) ұсынады. Алайда Java IEEE 754 стандартына толыққанды сәйкес келмейді. Көптеген C++ компиляторлары әдепкі бойынша IEEE 754 стандартына ішінара сәйкес келеді (әдетте қатаң дөңгелектеу ережелерін алып тастап, NaN нәтижелеріне ерекшеліктер жасайды), бірақ оңтайландыруға мүмкіндік беру үшін әртүрлі деңгейдегі сәйкестік опцияларын ұсынады. Егер осы опцияларды ең төменгі сәйкестіктен ең жоғары сәйкестікке дейін жылдам, дәйекті (Java-ның strictfp), IEEE-ге жақын және қатаң IEEE деп белгілесек, көптеген C++ жүзеге асырылымдары әдепкі бойынша IEEE-ге жақын екенін, жылдам немесе қатаң IEEE-ге ауысу опцияларымен, ал Java жылдам опциясымен дәйектіге ауыса алатынын айтуға болады. C++-та көрсеткіштерді жад адресі ретінде тікелей өңдеуге болады. Java сілтемелері нысандарға көрсеткіштер болып табылады. Java сілтемелері жад адресіне тікелей кіруге немесе көрсеткіш арифметикасымен жад адресін өңдеуге рұқсат бермейді. C++-та көрсеткіштерге көрсеткіштер, int және double-ға көрсеткіштер және кез келген жад орнына көрсеткіштер құруға болады. Java сілтемелері тек нысандарға ғана қол жеткізе алады, ешқашан примитивтерге, басқа сілтемелерге немесе кез келген жад орнына. Java-да жадқа кез келген мәнмен оқуға және жазуға болады sun.misc.Unsafe API арқылы, бірақ ол ескірген және ұсынылмайды. C++-та көрсеткіштер функцияларға немесе мүше функцияларға (функция көрсеткіштері) көрсетуі мүмкін. Java-дағы эквивалентті механизм нысан немесе интерфейс сілтемелерін қолданады. C++ стек арқылы бөлінген нысандар арқылы шектеулі ресурстарды басқаруды қолдайды, бұл жадты және басқа жүйелік ресурстарды автоматты түрде басқаруға арналған техника, ол нысандардың детерминистік жойылуын қамтамасыз етеді. C++-тағы шектеулі ресурстарды басқару кепілді емес (тіпті дұрыс жойғыштары бар нысандар да new арқылы бөлініп, жойылмай қалуы мүмкін), бірақ ол ресурстарды басқарудың тиімді құралы болып табылады. Ортақ ресурстарды shared_ptr арқылы басқаруға болады, сондай-ақ циклдық сілтемелерді бұзу үшін weak_ptr қолданылады. Java қоқыс жинау арқылы автоматты жадты басқаруды қолдайды, бұл қол жетімсіз нысандарды циклдық сілтемелер болған жағдайда да босатуға мүмкіндік береді, бірақ басқа жүйелік ресурстар (файлдар, ағындар, терезелер, байланыс порттары, жіптер және т.б.) қоқыс жинау дереу орындалмайтындықтан нақты түрде босатылуы керек. C++ пайдаланушы анықтаған операторларды жүктеуді қолдайды. Операторларды жүктеу пайдаланушы анықтаған типтерге примитивтер сияқты операторларды (арифметикалық, салыстыру және т.б.) пайдаланушы анықтаған жүзеге асырулар арқылы қолдауға мүмкіндік береді. Операторлардың семантикасын сақтау ұсынылады. Java операторларды жүктеудің ешқандай түрін қолдамайды (дегенмен, кітапханасы жолдарды тіркеу үшін қосым операторын пайдаланады). Java стандартты қолданбалық бағдарламалау интерфейсін (API) рефлексивті бағдарламалау (reflection) және кез келген жаңа кодты динамикалық түрде жүктеу үшін қолдайды. C++ бинарлық файлдарды статикалық және динамикалық байланыс арқылы қолдайды. Java generics-ке ие, оның басты мақсаты типтік қауіпсіз контейнерлерді ұсыну. C++ compile time templates-ке ие, ол generic бағдарламалау және метабағдарламалау үшін кеңрек қолдау көрсетеді. Java annotations-ке ие, ол сыныптарға кез келген қолданушы метадеректерді қосуға және annotation processing tool арқылы метабағдарламалауға мүмкіндік береді. Java және C++ жергілікті типтерді (немесе фундаменталды немесе құрастырылған типтер) және пайдаланушы анықтаған типтерді (немесе құрастырылған типтер) ажыратады. Java-да жергілікті типтерде тек мән семантикасы болады, ал құрастырылған типтерде тек сілтеме семантикасы болады. C++-та барлық типтерде мән семантикасы болады, бірақ кез келген типке сілтеме жасауға болады, бұл нысанды сілтеме семантикасы арқылы өңдеуге мүмкіндік береді. C++ кез келген сыныптардың көптеген мұрагерліктерін қолдайды. Java класы тек бір кластан туындай алады, бірақ бірнеше интерфейсті жүзеге асыруы мүмкін (басқаша айтқанда, ол типтердің көптеген мұрагерліктерін қолдайды, бірақ тек жүзеге асырудың бір мұрагерлігін ғана қолдайды). Java интерфейстер мен сыныптарды нақты ажыратады. C++-та көптеген мұрагерліктер және таза виртуалды функциялар Java интерфейстері сияқты жұмыс істейтін сыныптарды анықтауға мүмкіндік береді, бірақ бірнеше шағын айырмашылықтар бар. Java көп жіпті бағдарламалау үшін тіл және стандартты кітапхана қолдауын ұсынады. Java-дағы synchronized кілт сөзі көп жіпті қолданбаларды қолдау үшін mutex құлыптарын ұсынады. Java сондай-ақ одан да күрделі көп жіпті синхронизациялау үшін кітапханаларды ұсынады. C++11 C++-та көп жіптілік үшін анықталған жад моделіне және жіптерді жасауға және көптеген синхронизациялау примитивтеріне кітапханалық қолдауға ие. Бұл үшін көптеген үшінші тарап кітапханалары да бар. C++ мүше функцияларын виртуалды функциялар деп жариялауға болады, бұл шақырылатын әдіс нысанның орындалу уақытындағы түрімен анықталады (яғни динамикалық жіберу). Әдепкі бойынша C++ әдістері виртуалды емес (яғни виртуалды опцияны қосу). Java-да әдістер әдепкі бойынша виртуалды болады, бірақ final кілт сөзін пайдаланып виртуалды емес етуге болады (яғни виртуалды опцияны өшіру). C++ enumeration-дары примитивті типтер болып табылады және бүтін типтерге жасырын түрлендіруді қолдайды (бірақ бүтін типтерден емес). Java enumeration-дарын public static enum{enumName1,enumName2} түрінде жариялауға болады және олар сыныптар сияқты қолданылады. Басқа жолы, java.lang.Enum<E> класын кеңейтетін жаңа сынып жасауға болады және осылайша кез келген басқа сынып сияқты конструкторларды, өрістерді және әдістерді анықтауға болады. C++11 нұсқасынан бастап C++ күшті түрде тексерілген...

Ресурстарды басқару

Java автоматты түрде қоқыс жинауды ұсынады, оны нақты жағдайларда Java нақты уақыт спецификациясы арқылы айналып өтуге болады. C++-да жадты басқару әдетте конструкторлар, деструкторлар және смарт көрсеткіштер арқылы жүзеге асырылады. C++ стандарты қоқыс жинауға рұқсат береді, бірақ талап етпейді. Қоқыс жинау практикада сирек қолданылады. C++ жадтың кез келген блогын бөле алады. Java жадты тек объектіні құру арқылы бөледі. Java-да кез келген жад блогы байттар массиві ретінде бөлінуі мүмкін. Java және C++ ресурстарды басқару үшін әртүрлі тәсілдерді қолданады. Java негізінен жадыны қайтаруға қабілетті қоқыс жинауға сүйенеді, ал C++ негізінен Ресурсты алу – инициализациялау (RAII) тәсіліне сүйенеді. Бұл екі тілдің арасындағы бірнеше айырмашылықтарда көрінеді: C++-да күрделі типтегі объектілерді жергілікті стекке байланысты айнымалылар ретінде бөлу қалыпты жағдай, олар ауқымынан шыққанда жойылады. Java-да күрделі типтер әрқашан үйікте бөлінеді және қоқыс жинағышпен жиналады (құралды бөлуді стек бөлуіне аудару үшін құтылу талдауын қолданатын виртуалды машиналардан басқа). C++-да деструкторлар бар, ал Java-да финализаторлар бар. Екеуі де объектінің жойылмас бұрын шақырылады, бірақ олар айтарлықтай ерекшеленеді. C++ объектісінің деструкторын (стекке байланысты айнымалылар жағдайында) немесе объектіні жою үшін ашық түрде шақыру қажет. Деструктор объектінің жойылған бағдарламаның алдында синхронды түрде орындалады. C++-дағы синхронды, үйлестірілген инициализациялау және деаллокациялау RAII тәсілін қанағаттандырады. C++-тағы деструкторлар – объектпен байланысты ресурстарды қайтарудың қалыпты тәсілі және конструкторларға қажетті қарсылық. Java-да объектінің бөлінбеуін қоқыс жинағыш тікелей басқарады. Java объектісінің финализаторы соңғы рет қолжетімді болғаннан кейін және оны жоймас бұрын біраз уақыттан кейін асинхронды түрде шақырылады. Өте аз нысандар финализаторын қажет етеді. Финализерді тек объектінің күйін тазартуды қамтамасыз етуі керек объектілер ғана қажет, әдетте JVM-ге сыртқы ресурстарды босату. Финализаторларды тікелей пайдалану әдетте ұсынылмайды, өйткені олар болжауға болмайтын, әдетте қауіпті және көп жағдайда қажет емес. Финализаторларды C++ деструкторлары ретінде қарастырмау керек. Керісінше, ресурстармен жұмыс істеу немесе аяқтау блогы деструкторға ұқсас мақсатқа жетеді. Финализатордың немесе тазалаушының бір мәселесі – олардың бірден іске қосылатынына кепілдік берілмейді. Сондықтан, финализерді уақыт өте маңызды тапсырмалар үшін пайдаланбау керек. Сонымен қатар, финализаторлар орындалу жылдамдығын төмендетеді және нысандарды жоюға кететін уақытты едәуір арттырады, сондықтан оларды қолдану Java 9-да ұсынылмайды және тоқтатылды. C++-дағы RAII-де ресурстың бір түрі әдетте кішкентай сыныптың ішінде оралады, ол ресурсты құрастыру кезінде бөледі және ресурсты жою кезінде босатып, осы нүктелердің арасындағы ресурсқа қол жеткізуді қамтамасыз етеді. Тек осындай RAII объектілерін қамтитын кез келген сыныпқа деструкторды анықтаудың қажеті жоқ, өйткені RAII объектілерінің деструкторлары автоматты түрде осы сыныптың объектісі жойылған кезде шақырылады. Java-да ресурстарды қауіпсіз синхронды бөлу try/catch/finally конструкциясын пайдалану арқылы детерминистік түрде орындалуы мүмкін. Яғни, Java 7 бағдарламасында енгізілген ресурстармен жұмыс істеу конструкциясын try finally конструкциясының орнына қолдану керек. Ресурстармен жұмыс істеу конструкциясы қысқаша және оқуға ыңғайлы. Бұл сонымен қатар диагностикалық ақпаратты көбірек ұсынады, өйткені басқынған ерекшеліктер жойылмайды және стек ізінде басқынғандығы туралы ақпаратпен басылады. C++-да, бұрыннан бөлінген объектіге ескірген сілтеме болуы мүмкін. Айналасындағы меңзерді пайдалану әрекеті бағдарламаның сәтсіздігін тудырады. Java-да қоқыс жинағыш сілтеме жасалған объектіні жоймайды. C++-да бастапқы нысандарды инициализацияламау мүмкін. Java бастапқы инициализацияны орындайды. C++-да жарамды сілтемесі жоқ бөлінетін объектке ие болу мүмкін. Мұндай қол жеткізе алмайтын объектіні жоюға болмайды (бөлуден шығарылады) және ол жадтың ағуына әкеледі. Керісінше, Java-да объект (пайдаланушы бағдарламасына қол жеткізе алмайтын болғанша) қоқыс жинағышпен бөлінбейді. (Жарамсыз сілтемелер қолдайды, олар Java қоқыс жинағышымен жұмыс істейді, бұл қол жетімділіктің әртүрлі күштеріне мүмкіндік береді.) Java-дағы қоқыс жинау көптеген жад ағымдарын болдырмайды, бірақ кейбір жағдайларда ағымдар орын алуы мүмкін. Автоматты қоқыс жинағыш жадты басқару туралы ойлаудың қажеті жоқ деген жалған ой береді. Бірақ бұл толығымен дұрыс емес. Шартты түрде айтқанда, бағдарламада "жад ағымдары", немесе формальдырақ айтқанда, "керексіз объектілерді сақтау" болуы мүмкін. Жад ағымының мысалы – логикалық қателерсіз жазылған бағдарлама, бірақ ескі сілтемелерді жоймаған. Бұл қоқыс жинағыш белсенділігінің жоғарылауына, жадтың көбеюіне әкеледі. Шеткі жағдайларда бұл мәселе OutOfMemoryError-ға әкелуі мүмкін, бірақ бұл сирек кездеседі. Бұл мәселенің шешімі – объектілерге сілтемелерді null-ге орнату. Жад ағымының екінші себебі – енді қажет болмайтын кешті пайдалану. Ескі кештің салдарынан туындаған жад ағымдарын шешу үшін кешті WeakHashMap арқылы көрсету керек.

Кітапханалар

C++ платформаға тән кітапханаларда әдетте қол жетімді көптеген мүмкіндіктерге платформааралық қол жеткізуді қамтамасыз етеді. Java-дан операциялық жүйе мен аппараттық функцияларға тікелей қол жеткізу үшін Java Native интерфейсін пайдалану қажет.

Орындау уақыты

C++ Java C++ тікелей машиналық кодқа компиляцияланады, содан кейін оны орталық процессор тікелей орындайды. Java байт-кодқа компиляцияланады, оны Java виртуалды машинасы (JVM) орындалу кезінде интерпретациялайды. Java-ның нақты іске асырылымдары жергілікті машиналық кодқа уақыт компиляциясын жасайды. Оның шектелмеген мүмкіндіктеріне байланысты, C++ тілінің төменгі деңгейлі мүмкіндіктері (мысалы, тексерілмеген массивке кіру, шикі көрсеткіштер, типтік түрлендіру) компиляция кезінде немесе орындалу кезінде қосымша шығындарсыз сенімді түрде тексерілмейді. Осыған байланысты бағдарламалау қателері төменгі деңгейлі буфер асығуларына және сегментация қателеріне әкелуі мүмкін. Стандартты үлгілер кітапханасы (Standard Template Library) мұндай қателерді болдырмауға көмектесетін жоғары деңгейлі RAII абстракцияларын (мысалы, вектор, тізім және карта) ұсынады. Java-да төменгі деңгейлі қателер пайда болмайды немесе Java виртуалды машинасы (JVM) оларды анықтап, қосымшаға ерекшелік түрінде хабарлайды. Java тілі массивке шектен тыс кіру жағдайында нақты мінез-құлықты талап етеді, бұл әдетте массивке кірулерді тексеруді қажет етеді. Бұл тұрақсыздықтың мүмкін көзін жояды, бірақ әдетте орындалу жылдамдығын төмендетеді. Кейбір жағдайларда, әсіресе Java 7-ден бастап, компилятор талдауы шектерді тексерудің қажетсіз екенін дәлелдеп, оны жоюы мүмкін. C++ тілінде жергілікті массивтерге шектен тыс кіру үшін талап етілетін мінез-құлық жоқ, сондықтан жергілікті массивтерді тексеру қажет емес. Дегенмен, std::vector сияқты C++ стандартты кітапхана коллекциялары опциялық шектерді тексеруді ұсынады. Қорыта айтқанда, Java массивтері "әдетте қауіпсіз; сәл шектелген; көбінесе қосымша шығындарға ие", ал C++ жергілікті массивтері "қосымша шығындарға ие болуы мүмкін; сәл шектелмеген; қауіпсіз болмауы мүмкін".

Әр түрлі

Java және C++ кодты бірнеше бастапқы файлдарға бөлу үшін әртүрлі тәсілдерді қолданады. Java барлық бағдарламалық анықтамалар үшін файлдың атауы мен жолын анықтайтын пакет жүйесін қолданады. Оның компиляторы орындалатын сынып файлдарын импорттайды. C++ бастапқы файлдар арасындағы жарияланымдарды бөлісу үшін бас файлдың бастапқы кодты қосу жүйесін қолданады. Компиляцияланған Java код файлдары әдетте C++ код файлдарынан кішірек болады, себебі Java байт-коды көбінесе түпкілікті машиналық кодтан ықшамдау, ал Java бағдарламалары ешқашан статикалық байланысқа түспейді. C++ компиляциясы қосымша мәтіндік алдын ала өңдеу фазасын қамтиды, ал Java-да мұндай фаза жоқ. Сондықтан кейбір қолданушылар жақсырақ шартты компиляция қолдауы үшін құрастыру процесіне алдын ала өңдеу фазасын қосады. Java-ның бөлу және қалдық операторлары нөлге қарай дөңгелеу үшін нақты анықталған. C++ (C++11-ге дейін) бұл операторлардың нөлге немесе «шексіздікке қарай дөңгелеуге» дөңгеленетінін нақтыламады. 3/2 Java және C++11-де әрқашан 1 болады, бірақ C++03 компиляторы платформаға байланысты 1 немесе 2 қайтара алады. C99 Java және C++11 сияқты бөлуді анықтайды. Екі тіл де (a және b бүтін сан түрлері болғанда) (a/b)*b + (a%b) == a екенін барлық a және b үшін (b != 0) кепілдік береді. C++03 нұсқасы кейде жылдамырақ болады, себебі ол процессорға тән кез келген дөңгелеу режимін таңдауға рұқсат етіледі. Бүтін сан түрлерінің мөлшері Java-да анықталған (int - 32 бит, long - 64 бит), ал C++-да сандар мен көрсеткіштердің мөлшері компилятор мен қолданбаның екілік интерфейсіне (ABI) байланысты. Осылайша Java бағдарламасы платформалар бойынша тұрақты мінез-құлық көрсетеді, ал C++ бағдарламасы кейбір платформалар үшін бейімделуді қажет етуі мүмкін, бірақ жергілікті платформа үшін табиғи бүтін сан мөлшерлерімен жылдамырақ жұмыс істеуі мүмкін. C++ және Java-ны салыстыратын мысал Wikibooks-та бар.

Тілдің ерекшеліктері

C++ тілі ISO/IEC 14882 стандартымен анықталады, оны ISO/IEC JTC1/SC22/WG21 комитеті жариялайды. C++17 стандартынан кейінгі соңғы нұсқасы да қолжетімді. C++ тілі C++ стандарттар комитеті деп аталатын ашық басқару комитеті арқылы дамиды. Комитет құрамына C++ тілін жасаған Бьярн Строструп, төраға Херб Саттер және басқа да көрнекті тұлғалар кіреді, соның ішінде көптеген өнеркәсіптер мен пайдаланушылар тобының өкілдері (яғни, мүдделі тараптар). Ашық комитет болғандықтан, кез келген адам оған қосылып, қатысып, стандарттың және техникалық сипаттамалардың болашақ нұсқаларына ұсыныстар енгізе алады. Комитет қазір бірнеше жылда бір рет жаңа стандарт шығаруды көздейді, бірақ бұрынғы қатаң тексеру процестері мен талқылаулар жаңа стандарттарды жариялау арасында ұзақ кешігуге әкеп соқты (1998, 2003 және 2011 жылдар). Java тілі Oracle баспасынан шыққан Java тілінің сипаттамасы (Java Language Specification) кітабында анықталады. Java тілі Java Community Process деп аталатын үдеріс арқылы үздіксіз дамиды, ал әлемдік бағдарламалау қауымдастығын Java Community мүшелері деп аталатын адамдар мен ұйымдар тобы білдіреді, олар тілді жақсартуға белсенді қатысады, Java тілінің сипаттамасына енгізілмес бұрын ресми және қоғамдық тексеруден өтуі тиіс Java сипаттамалық сұраныстарын (Java Specification Requests) жіберіп. Java үшін нақты стандарттың болмауы және оның сипаттамаларының біршама тұрақсыздығы жаңа тіл және кітапхана мүмкіндіктерін қосуда көбірек тұрақтылық пен консервативтік талап ететін мүдделі тараптардың үнемі сынына ұшырады. Керісінше, C++ комитеті де қарсы себеппен, яғни тым қатаң және консервативті болуы және жаңа нұсқаларды шығаруға тым көп уақыт жұмсауы себепті тұрақты сыни пікірлерге ие болады.

Тауар белгілері

"C++" ешбір компанияның немесе ұйымның тауарлық белгісі емес және ешкімнің меншігінде болмайды. "Java" – Oracle Corporation компаниясының тауарлық белгісі.