Сравнение Java и C ++

редактировать

Это сравнение Java и C ++, два выдающихся объектно-ориентированных языков программирования.

Содержание

  • 1 Цели проектирования
  • 2 Языковые особенности
    • 2.1 Синтаксис
    • 2.2 Семантика
    • 2.3 Управление ресурсами
    • 2.4 Библиотеки
    • 2.5 Время выполнения
    • 2.6 Шаблоны и универсальные шаблоны
    • 2.7 Разное
  • 3 Производительность
  • 4 Официальный стандарт и справочник языка
    • 4.1 Спецификация языка
    • 4.2 Товарные знаки
  • 5 Ссылки
  • 6 Внешние ссылки

Цели дизайна

Различия между языками программирования C ++ и Java можно проследить до их наследия, поскольку они имеют разные цели дизайна.

C ++ был разработан для программирования систем и приложений (т.е. программирования инфраструктуры), расширяя процедурное программирование язык C, который был разработан для эффективного выполнения. В C в C ++ добавлена ​​поддержка объектно-ориентированного программирования, обработки исключений, управления ресурсами на основе времени жизни (RAII ), общего программирования, метапрограммирование шаблонов и Стандартная библиотека C ++, которая включает общие контейнеры и алгоритмы (Стандартная библиотека шаблонов или STL), а также многие другие средства общего назначения.

Java - это универсальный, параллельный, объектно-ориентированный язык программирования на основе классов, который разработан для минимизации зависимостей реализации. Он полагается на виртуальную машину Java, чтобы быть защищенной и очень портативной. Он поставляется в комплекте с обширной библиотекой, предназначенной для обеспечения полной абстракции базовой платформы. Java - это объектно-ориентированный язык со статической типизацией, использующий синтаксис, аналогичный (но несовместимый с) C ++. Он включает систему документации под названием Javadoc.

. Различные цели в разработке C ++ и Java привели к разным принципам и компромиссам дизайна между языками. Различия заключаются в следующем:

C ++Java
Расширяет C с помощью объектно-ориентированного программирования и общего программирования. Наиболее правильно можно использовать код C.Сильно зависит от синтаксиса C ++ / C.
Совместим с исходным кодом C, за исключением нескольких угловых случаев.Предоставляет собственный интерфейс Java и недавно Java Native Access как способ прямого вызова кода C / C ++.
Напишите один раз, скомпилируйте где угодно (WOCA).Пишите один раз, запускайте где угодно / везде (WORA / WORE).
Позволяет процедурное программирование, функциональное программирование, объектно-ориентированное программирование, общее программирование и метапрограммирование шаблонов. Выступает за сочетание парадигм.Разрешает процедурное программирование, функциональное программирование (начиная с Java 8) и общее программирование (начиная с Java 5), ​​но настоятельно рекомендует объектно-ориентированное парадигма программирования. Включает поддержку создания языков сценариев.
Выполняется как собственный исполняемый машинный код для целевого набора команд (ов).Работает на виртуальной машине.
Предоставляет типы объектов и имена типов. Допускает отражение через информацию о типе времени выполнения (RTTI).Является отражающим, что позволяет метапрограммировать и генерировать динамический код во время выполнения.
Имеет несколько стандартов двоичной совместимости (обычно Microsoft (для компилятора MSVC) и Itanium / GNU (почти для всех других компиляторов)).Имеет один стандарт двоичной совместимости, кросс-платформенный для ОС и компилятора.
Необязательная автоматическая проверка границ (например, метод at ()в контейнерах vectorи string).Все операции должны проходить обязательную проверку всеми совместимыми дистрибутивами Java. HotSpot может убрать проверку границ.
Собственная поддержка беззнаковой арифметики.Нативная арифметика без знака не поддерживается. Java 8 меняет некоторые из этого, но аспекты неясны.
Стандартизированные минимальные ограничения для всех числовых типов, но фактические размеры определяются реализацией. Стандартизированные типы доступны через стандартную библиотеку .Стандартизированные пределы и размеры всех примитивных типов на всех платформах.
Указатели, ссылки и передача по значению поддерживаются для всех типов (примитивных или определяемых пользователем).Все типы (примитивные типы и ссылочные типы) всегда передаются по значению.
Управление памятью можно выполнять вручную через new / delete, автоматически по области действия или интеллектуальным указателям. Поддерживает детерминированное разрушение объектов. Сборка мусора ABI стандартизирован в C ++ 11, хотя компиляторы не обязаны реализовывать сборку мусора.Автоматическая сборка мусора. Поддерживает недетерминированный метод finalize (), использование которого не рекомендуется.
Управление ресурсами может выполняться вручную или с помощью автоматического управления ресурсами на основе времени жизни (RAII ).Управление ресурсами обычно должно выполняться вручную или автоматически с помощью финализаторов, хотя обычно это не рекомендуется. Имеет try-with-resources для автоматического управления ресурсами на основе области (начиная с версии 7).

Это также можно сделать с помощью внутреннего API sun.misc.Unsafe, но такое использование крайне не рекомендуется и будет заменено общедоступным API в следующей версии Java.

Поддерживает классы, структуры (типы пассивных структур данных (PDS)) и объединения и может размещать их в куче или стеке.Классы размещены в куче . Java SE 6 оптимизируется с помощью escape-анализа для выделения некоторых объектов в стеке .
Позволяет явно переопределять типы и некоторые неявные сужающие преобразования (для совместимости с C).Жесткий типобезопасность, за исключением расширяющих преобразований.
Стандартная библиотека C ++ была разработана с учетом ограниченного объема и функций, но включает поддержку языка, диагностику, общие утилиты, строки, языковые стандарты, контейнеры, алгоритмы, итераторы, числа, ввод / вывод, генераторы случайных чисел, синтаксический анализ регулярных выражений, средства многопоточности, характеристики типов (для самоанализа статических типов) и стандартная библиотека C. Библиотека Boost предлагает больше функций, включая сетевой ввод-вывод.

Существует большое количество сторонних библиотек для графического интерфейса пользователя и других функций, таких как: Adaptive Communication Environment (ACE), Crypto ++, различные XMPP Библиотеки мгновенного обмена сообщениями (IM), OpenLDAP, Qt, gtkmm.

Стандартная библиотека расширяется с каждым выпуском. К версии 1.6 библиотека включала поддержку локалей, журналов, контейнеров и итераторов, алгоритмов, программирования графического интерфейса (но без использования системного графического интерфейса), графики, многопоточности, сети, безопасности платформы, самоанализа, загрузки динамических классов, блокировки и отсутствия -блокировка ввода / вывода. Он предоставил интерфейсы или классы поддержки для XML, XSLT, MIDI, подключения к базе данных, служб именования (например, LDAP ), криптографии, безопасности службы (например, Kerberos ), службы печати и веб-службы. SWT предлагал абстракцию для графических интерфейсов, зависящих от платформы, но в последних версиях был заменен на JavaFX ; возможность ускорения графики и пользовательских интерфейсов с поддержкой CSS. Хотя он не поддерживает какую-либо поддержку «родного вида платформы».
Перегрузка оператора для большинства операторов. Настоятельно рекомендуется сохранять значение (семантику).Операторы не могут быть изменены. Язык отменяет + и + = для класса String.
Одиночное и множественное наследование классов, включая виртуальное наследование.Поддерживает только одиночное наследование классов.
Шаблоны времени компиляции. Позволяет завершить метапрограммирование по Тьюрингу.Generics используются для достижения базовой параметризации типа, но они не преобразуются из исходного кода в байтовый код из-за использования компилятором стирания типа.
Указатели на функции, объекты функций, лямбда-выражения (в C ++ 11 ) и интерфейсы.Ссылки на функции, объекты функций и лямбда-выражения были добавлены в Java 8. Классы (и интерфейсы, которые являются классами) также могут передаваться как ссылки через SomeClass.class
Отсутствует стандартный механизм встроенной документации. Существует стороннее программное обеспечение (например, Doxygen ).Обширный стандарт документации Javadoc для всех системных классов и методов.
constключевое слово для определения неизменяемых переменных и функций-членов, которые не изменяют объект. Постоянство распространяется как средство обеспечения во время компиляции правильности кода в отношении изменчивости объектов (см. const-correction ).finalпредоставляет версию const, эквивалентную указателям type * constдля объектов и constдля примитивных типов. Неизменяемость членов объекта достигается с помощью интерфейсов только для чтения иинкапсуляции объектов.
Поддерживает оператор goto .Поддерживает метки с циклами и блоками операторов. goto- зарезервированное ключевое слово, но помечено как "неиспользуемое" в спецификации Java.
Исходный код может быть записан как кроссплатформенный (может быть скомпилирован для Windows, BSD, Linux, macOS, Solaris и т. Д., Без изменений) и написаны для использования особенности платформы. Обычно компилируется в машинный код, его необходимо перекомпилировать для каждой целевой платформы.Скомпилировано в байт-код Java для JVM. Байт-код зависит от платформы Java, но обычно не зависит от конкретных функций операционной системы.

Возможности языка

Синтаксис

  • Синтаксис Java имеет контекстно-свободную грамматику, которая может быть проанализирована простым анализатором LALR. Парсинг C ++ сложнее. Например, Foo <1>(3);- это последовательность сравнений, если Foo является переменной, но создает объект, если Foo является именем шаблона класса.
  • C ++ допускает константы, переменные и функции на уровне пространства имен. В Java такие сущности должны принадлежать какому-либо заданному типу и, следовательно, должны быть определены внутри определения типа, либо класса, либо интерфейса .
  • В C ++ объекты являются значениями, а в Java - нет. C ++ по умолчанию использует семантику значений, тогда как Java всегда использует ссылочную семантику. Чтобы выбрать семантику ссылок в C ++, можно использовать указатель или ссылку.
C ++Java
class Foo {// Объявляет class Foo int x = 0; // Переменная частного члена. Он будет // инициализирован в 0, если // конструктор не установил его. // (из C ++ 11) public: Foo (): x (0) // Конструктор для Foo; инициализирует {} // x значением 0. Если бы инициализатор был // опущен, переменная // была бы инициализирована значением, которое // было присвоено при объявлении x. int bar (int i) {// Функция-член bar () return 3 * i + x; }};
class Foo {// Определяет class Foo private int x; // Переменная-член, обычно объявленная // как закрытая для принудительной инкапсуляции // инициализированная 0 по умолчанию public Foo () {// Конструктор для Foo} // конструктор без аргументов, предоставленный по умолчанию public int bar (int i) {/ / Элемент метода bar () return 3 * i + x; }}
Foo a; // объявляет, что a является значением объекта Foo, // инициализируемым с помощью конструктора по умолчанию. // Другой конструктор можно использовать как Foo a (args); // или (C ++ 11): Foo a {args};
Foo a = новый Foo (); // объявляет, что a является ссылкой на новый объект Foo, // инициализированный с помощью конструктора по умолчанию // Другой конструктор может использоваться как Foo a = new Foo (args);
Foo b = a; // копирует содержимое a в новый объект Foo b; // альтернативный синтаксис: «Foo b (a)»
// Foo b = a; // объявил бы b ссылкой на объект, на который указывает Foo b = a.clone (); // копирует содержимое объекта, на который указывает //, в новый объект Foo; // устанавливает ссылку b, указывающую на этот новый объект; // класс Foo должен реализовать интерфейс Cloneable // для компиляции этого кода
a.x = 5; // изменяет объект a
a.x = 5; // изменяет объект, на который ссылается
std :: cout << b.x << std::endl; // outputs 0, because b is // some object other than a
System.out.println (b.x); // выводит 0, потому что b указывает // на какой-то объект, отличный от a
Foo * c; // объявляет c как указатель на // объект Foo (изначально // не определено; может указывать куда угодно)
Foo c; // объявляет c как ссылку на объект Foo // (изначально null, если c является членом класса; // необходимо инициализировать c перед использованием // если это локальная переменная)
c = new Foo ; // c устанавливается в значение адреса объекта Foo, созданного оператором new
c = new Foo (); // связывает c для ссылки на новый объект Foo
Foo d = * c; // связывает d для ссылки на тот же объект, на который указывает c
Foo d = c; // связывает d для ссылки на тот же объект, что и c
c->x = 5; // изменяет объект, на который указывает c
c.x = 5; // изменяет объект, на который ссылается c
d.bar (5); // вызывает Foo :: bar () для c->bar (5); // вызывает Foo :: bar () для * c
d.bar (5); // вызывает Foo.bar () для c.bar (5); // вызывает Foo.bar () для c
std :: cout << d.x << std::endl; // outputs 5, because d references the // same object to which c points
System.out.println (d.x); // выводит 5, потому что d ссылается на // тот же объект, что и c
  • . В C ++ можно объявить указатель или ссылку на объект const, чтобы предотвратить его изменение клиентским кодом. Функции и методы также могут гарантировать, что они не будут изменять объект, на который указывает указатель, с помощью ключевого слова «const». Это обеспечивает константную корректность.
  • В Java, по большей части, константная корректность должна полагаться на семантику интерфейса класса, т. Е. Она не строго соблюдается, за исключением общедоступных элементов данных, которые помечены final.
C ++Java
const Foo * a; // невозможно изменить объект, // на который указывает a через Foo * const a = new Foo; // Объявление константного указателя: // объект можно изменить, // но указатель будет постоянно указывать // на назначенный ему здесь объект
final Foo a; // объявление "окончательной" ссылки: // объект можно изменить, // но ссылка будет постоянно указывать // на первый назначенный ему объект
a = new Foo ();
a = новый Foo (); // Только в конструкторе
a->x = 5; // НЕЗАКОННЫЙ
a.x = 5; // ЛЕГАЛЬНО, члены объекта все еще могут быть изменены // если явно не объявлено final в объявляющем классе
Foo * const b = new Foo (); // объявление "константного" указателя
final Foo b = new Foo (); // объявление «последней» ссылки
b = new Foo (); // НЕЗАКОННО, его нельзя повторно привязать
b = new Foo (); // НЕЗАКОННО, перепривязать нельзя
b->x = 5; // ЮРИДИЧЕСКИЙ, объект все еще можно изменить
b.x = 5; // ЮРИДИЧЕСКИЙ, объект все еще может быть изменен
  • C ++ поддерживает операторы goto , что может привести к программированию спагетти-кода. За исключением оператора goto (который очень редко встречается в реальном коде и крайне не рекомендуется), как Java, так и C ++ имеют в основном одинаковые структуры потока управления , разработан для обеспечения выполнения структурированного потока управления и использует операторы break и continue для предоставления некоторых функций, подобных goto. Некоторые комментаторы отмечают, что эти помеченные операторы управления потоком нарушают свойство единой точки выхода структурного программирования.
  • C ++ предоставляет низкоуровневые функции, которых нет в Java. В C ++ указатели могут использоваться для управления определенными ячейками памяти - задача, необходимая для написания низкоуровневых компонентов операционной системы. Точно так же многие компиляторы C ++ поддерживают встроенный ассемблер . Код на языке ассемблера можно импортировать в программу C и наоборот. Это делает язык Си еще быстрее. В Java такой код должен находиться во внешних библиотеках, и к нему можно получить доступ только через собственный интерфейс Java, со значительными накладными расходами для каждого вызова.

Семантика

  • C ++ допускает значения по умолчанию для аргументов функция / метод. Java - нет. Однако перегрузка метода может использоваться для получения аналогичных результатов в Java, но для генерации избыточного кода-заглушки.
  • Минимум кода, необходимого для компиляции для C ++, - это функция, для Java - это класс.
  • C ++ допускает ряд неявных преобразований между собственными типами (включая некоторые сужающие преобразования), а также позволяет определять неявные преобразования, включающие определяемые пользователем типы. В Java неявными являются только расширяющиеся преобразования между собственными типами; другие преобразования требуют явного синтаксиса приведения.
    • Результатом этого является то, что хотя условия цикла (if, whileи условие выхода в для) в Java и C ++ оба ожидают логического выражения, код, такой как if (a = 5)вызовет ошибку компиляции в Java, потому что не существует неявного сужающего преобразования из int в логическое значение, но будет компилироваться на C ++. Это удобно, если код был опечаткой и , если (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 ++ можно создавать указатели на указатели, указатели на целые и двойные числа, а также указатели на произвольные ячейки памяти. Ссылки Java обращаются только к объектам, но не к примитивам, другим ссылкам или произвольным ячейкам памяти.
  • В C ++ указатели могут указывать на функции или функции-члены (указатели на функции ). Эквивалентный механизм в Java использует ссылки на объекты или интерфейсы.
  • С помощью объектов, выделенных стеком, C ++ поддерживает управление ресурсами с заданной областью, метод, используемый для автоматического управления памятью и другими системными ресурсами, который поддерживает детерминированный объект разрушение. Хотя управление ресурсами с ограниченным объемом в C ++ не может быть гарантировано (даже объекты с соответствующими деструкторами могут быть выделены с помощью newи оставлены без удаления), оно обеспечивает эффективное средство управления ресурсами. Общими ресурсами можно управлять с помощью shared_ptrвместе с weak_ptrдля разрыва циклических ссылок. Java поддерживает автоматическое управление памятью с использованием сборки мусора, которая может освобождать недоступные объекты даже при наличии циклических ссылок, но другие системные ресурсы (файлы, потоки, окна, порты связи, потоки и т. Д.) Должны быть явно освобождены поскольку сборка мусора не гарантируется сразу после отказа от последней ссылки на объект.
  • В C ++ предусмотрена перегрузка определяемого пользователем оператора . Перегрузка операторов позволяет определяемым пользователем типам поддерживать операторы (арифметические, сравнения и т. Д.), Такие как примитивные типы, через определяемые пользователем реализации этих операторов. Обычно рекомендуется сохранять семантику операторов. Java не поддерживает никаких форм перегрузки операторов (хотя в ее библиотеке используется оператор сложения для конкатенации строк).
  • Java имеет стандартный интерфейс прикладного программирования (API), поддерживающий отражение и динамическая загрузка произвольного нового кода.
  • C ++ поддерживает статическое и динамическое связывание двоичных файлов.
  • Java имеет универсальные шаблоны, основная цель которых - обеспечить типобезопасные контейнеры. В C ++ есть шаблоны времени компиляции, которые обеспечивают более широкую поддержку общего программирования и метапрограммирования. В Java есть аннотации, которые позволяют добавлять произвольные пользовательские метаданные к классам и метапрограммировать с помощью инструмента обработки аннотаций .
  • И Java, и C ++ различают собственные типы (также называемые фундаментальными или встроенными типами) и определяемые пользователем типы (также называемые составными типами). В Java собственные типы имеют только семантику значений, а составные типы имеют только ссылочную семантику. В C ++ все типы имеют семантику значений, но можно создать ссылку на любой тип, что позволит управлять объектом с помощью семантики ссылок.
  • C ++ поддерживает множественное наследование произвольных классов. В Java класс может быть производным только от одного класса, но класс может реализовывать несколько интерфейсов (другими словами, он поддерживает множественное наследование типов, но только одно наследование реализации).
  • Java явно различает интерфейсы и классы. В C ++ множественное наследование и чисто виртуальные функции позволяют определять классы, которые работают почти так же, как интерфейсы Java, с некоторыми небольшими отличиями.
  • Java поддерживает как язык, так и стандартные библиотеки для многопоточности. Ключевое слово synchronizedв Java обеспечивает простые и безопасные блокировки мьютекса для поддержки многопоточных приложений. Java также предоставляет надежные и сложные библиотеки для более продвинутой многопоточной синхронизации. Только с C ++ 11 существует определенная модель памяти для многопоточности в C ++ и поддержка библиотек для создания потоков и многих синхронизирующих примитивов. Для этого также существует множество сторонних библиотек.
  • Функции-члены C ++ могут быть объявлены как виртуальные функции, что означает, что вызываемый метод определяется типом времени выполнения объект (он же динамическая диспетчеризация). По умолчанию методы в C ++ не являются виртуальными (то есть виртуальными по подписке). В Java методы являются виртуальными по умолчанию, но их можно сделать не виртуальными с помощью ключевого слова final (т.е. виртуального отказа).
  • Перечисления C ++ являются примитивными типами и поддерживают неявное преобразование в целочисленные типы (но не из целочисленных типов). Перечисления Java могут быть общедоступным статическим перечислением {enumName1, enumName2}и используются как классы. Другой способ - создать другой класс, который расширяет java.lang.Enum) и поэтому может определять конструкторы, поля и методы, как любой другой класс. Начиная с C ++ 11, C ++ также поддерживает строго типизированные перечисления, которые обеспечивают большую безопасность типов и явную спецификацию типа хранилища.
  • Унарные операторы '+ + 'и' - ': в C ++ "Операнд должен быть изменяемым lvalue. [пропущено] Результатом является обновленный операнд; это lvalue...", но в Java "двоичный Упомянутое выше числовое продвижение может включать преобразование распаковки и преобразование набора значений. При необходимости преобразование набора значений {и / или [...] преобразование упаковки} применяется к сумме до ее сохранения в переменной. ", то есть в Java., после инициализации "Integer i = 2;", "++ i;" изменяет ссылку i, назначая новый объект, в то время как в C ++ объект остается прежним.

Управление ресурсами

  • Java предлагает автоматическую сборку мусора, которую в определенных обстоятельствах можно обойти с помощью Спецификация Java в реальном времени. Управление памятью в C ++ обычно осуществляется с помощью конструкторов, деструкторов и интеллектуальных указателей. Стандарт C ++ разрешает сборку мусора, но не требует этого. На практике сборка мусора используется редко.
  • C ++ может выделять произвольные блоки памяти. Java выделяет память только через создание экземпляров объекта. Произвольные блоки памяти могут быть выделены в Java как массив байтов.
  • Java и C ++ используют разные идиомы для управления ресурсами. Java в основном полагается на сборку мусора, которая может освободить память, в то время как C ++ в основном полагается на идиому Resource Acquisition Is Initialization (RAII). Это отражено в нескольких различиях между двумя языками:
    • В C ++ принято выделять объекты составных типов как локальные переменные, привязанные к стеку, которые уничтожаются, когда они выходят за пределы области видимости. В Java составные типы всегда выделяются в куче и собираются сборщиком мусора (за исключением виртуальных машин, которые используют escape-анализ для преобразования выделения кучи в выделение стека).
    • C ++ имеет деструкторы, а в Java есть финализаторы. Оба вызываются перед освобождением объекта, но они значительно отличаются. Деструктор объекта C ++ должен вызываться неявно (в случае переменных, привязанных к стеку) или явно для освобождения объекта. Деструктор выполняет синхронно непосредственно перед точкой в ​​программе, в которой объект освобождается. Таким образом, синхронная, скоординированная деинициализация и освобождение в C ++ удовлетворяет идиоме RAII. В Java освобождение объекта неявно обрабатывается сборщиком мусора. Финализатор Java-объекта вызывается асинхронно через некоторое время после последнего обращения к нему и до его освобождения. Очень немногие объекты нуждаются в финализаторах. Финализатор нужен только объектам, которые должны гарантировать некоторую очистку состояния объекта перед освобождением, обычно освобождая ресурсы, внешние по отношению к JVM.
    • С RAII в C ++ один тип ресурса обычно заключен в небольшой класс, который распределяет ресурс при создании и высвобождает ресурс при уничтожении, а также предоставляет доступ к ресурсу между этими точками. Любой класс, который содержит только такие объекты RAII, не нуждается в определениидеструктора, поскольку деструкторы объектов RAII вызываются автоматически при уничтожении объекта этого класса. В Java безопасное синхронное освобождение ресурсов может быть выполнено детерминированно с помощью конструкции try / catch / finally.
    • В C ++ можно иметь висячий указатель, устаревший ссылка на объект, который уже был освобожден. Попытка использовать висящий указатель обычно приводит к сбою программы. В Java сборщик мусора не уничтожает объект, на который имеется ссылка.
    • В C ++ можно иметь неинициализированные примитивные объекты. Java выполняет инициализацию по умолчанию.
    • В C ++ можно иметь выделенный объект, на который нет действительной ссылки. Такой недостижимый объект не может быть уничтожен (освобожден) и приводит к утечке памяти. Напротив, в Java объект не будет освобожден сборщиком мусора до тех пор, пока он не станет недоступным (для пользовательской программы). (Поддерживаются слабые ссылки, которые работают со сборщиком мусора Java, чтобы обеспечить различную степень достижимости.) Сборка мусора в Java предотвращает многие утечки памяти, но при некоторых обстоятельствах утечки все же возможны.

Библиотеки

  • C ++ предоставляет кроссплатформенный доступ ко многим функциям, обычно доступным в библиотеках для конкретных платформ. Прямой доступ из Java к собственной операционной системе и аппаратным функциям требует использования Java Native Interface.

Runtime

C ++Java
C ++ компилируется непосредственно в машинный код , который затем выполняется непосредственно центральным процессором.Java компилируется в байт-код, который виртуальная машина Java (JVM) затем интерпретирует во время выполнения. Фактические реализации Java выполняют своевременную компиляцию собственного машинного кода. В качестве альтернативы компилятор GNU для Java может компилироваться непосредственно в машинный код.
  • Из-за безграничной выразительности низкоуровневые функции языка C ++ (например, непроверенный доступ к массиву, необработанные указатели, каламбур ) не могут быть надежно проверены во время компиляции или без накладных расходов во время выполнения. Связанные с этим ошибки программирования могут привести к низкоуровневому переполнению буфера и ошибкам сегментации. Стандартная библиотека шаблонов предоставляет абстракции RAII более высокого уровня (например, вектор, список и карту), чтобы помочь избежать таких ошибок. В Java ошибки низкого уровня либо не могут возникать, либо обнаруживаются виртуальной машиной Java (JVM) и сообщаются приложению в виде исключения.
  • . Для языка Java требуется особое поведение в случай доступа к массиву за пределами границ, который обычно требует проверка границ доступа к массиву. Это устраняет возможный источник нестабильности, но обычно за счет замедления выполнения. В некоторых случаях, особенно после Java 7, анализ компилятора может доказать ненужность проверки границ и устранить ее. C ++ не имеет требуемого поведения для доступа за пределы собственных массивов, поэтому не требует проверки границ для собственных массивов. Однако коллекции стандартной библиотеки C ++, такие как std :: vector, предлагают дополнительную проверку границ. Таким образом, массивы Java "обычно безопасны; слегка ограничены; часто имеют накладные расходы", в то время как собственные массивы C ++ "имеют необязательные накладные расходы; немного не ограничены; возможно, небезопасны".

Шаблоны и универсальные шаблоны

Оба C ++ и Java предоставляют средства для универсального программирования, шаблонов и универсальных шаблонов соответственно. Хотя они были созданы для решения аналогичных задач и имеют похожий синтаксис, они совершенно разные.

Шаблоны C ++Универсальные шаблоны Java
Можно создавать шаблоны для классов, функций, псевдонимов и переменных.Классы и методы могут быть универсальными.
Параметры могут быть вариативными, любого типа, целочисленного значения, символьного литерала или шаблона класса.Параметры могут быть любого ссылочного типа, включая примитивные типы в штучной упаковке (например, Integer, Boolean...).
При компиляции для каждого набора параметров будут созданы отдельные экземпляры класса или функции. Для шаблонов классов будут созданы экземпляры только используемых функций-членов.Компилируется одна версия класса или функции, работает для всех параметров типа (через стирание типа).
Объекты шаблона класса, экземпляры которого созданы с разными параметрами, будут иметь разные типы во время выполнения (т. Е. Отдельные экземпляры шаблона являются отдельными классами).Параметры типа стираются при компиляции; объекты класса с разными параметрами типа являются одним и тем же типом во время выполнения. Это вызывает другой конструктор. Из-за стирания этого типа невозможно перегрузить методы, используя различные экземпляры универсального класса.
Реализация шаблона класса или функции должна быть видна в единице перевода, чтобы ее можно было использовать. Обычно это подразумевает наличие определений в файлах заголовков или включение в файл заголовков. Начиная с C ++ 11, можно использовать шаблоны extern для разделения компиляции некоторых экземпляров.Для использования достаточно сигнатуры класса или функции из скомпилированного файла класса.
Шаблоны могут быть специализированными - для отдельного параметра шаблона может быть предусмотрена отдельная реализация.Универсальные шаблоны нельзя специализировать.
Параметры шаблона могут иметь аргументы по умолчанию. До C ++ 11 это было разрешено только для классов шаблонов, но не для функций.Параметры универсального типа не могут иметь аргументы по умолчанию.
Подстановочные знаки не поддерживаются. Вместо этого возвращаемые типы часто доступны как вложенные typedef. (Кроме того, в C ++ 11 добавлено ключевое слово auto, которое действует как подстановочный знак для любого типа, который может быть определен во время компиляции.)Подстановочные знаки поддерживаются как тип параметр.
Нет прямой поддержки ограничения параметров типа, но это обеспечивает метапрограммирование.Поддерживает ограничение параметров типа с помощью "extends" и "super" для верхней и нижней границ соответственно; позволяет устанавливать отношения между параметрами типа.
Разрешает создание экземпляра объекта с типом типа параметра.Исключает создание экземпляра объекта с типом типа параметра (кроме как через отражение).
Параметр типа шаблона класса может использоваться для статических методов и переменных.Параметр типа универсального класса нельзя использовать для статических методов и переменных.
Статические переменные не используются совместно классами и функциями с параметрами разных типов.Статические переменные, совместно используемые экземплярами классов с параметрами разных типов.
Шаблоны классов и функций не устанавливают отношения типов для параметров типа в своем объявлении. Использование неверного параметра типа приводит к сбою компиляции, часто генерируя сообщение об ошибке в коде шаблона, а не в коде пользователя, который его вызывает. Правильное использование шаблонных классов и функций зависит от надлежащей документации. Метапрограммирование предоставляет эти функции за счет дополнительных усилий. Было предложение решить эту проблему в C ++ 11, так называемые Concepts, это планируется в следующем стандарте.Универсальные классы и функции могут устанавливать отношения типов для параметров типа в своем объявлении. Использование неверного параметра типа приводит к ошибке типа в коде, который его использует. Операции с параметризованными типами в универсальном коде разрешены только способами, безопасность которых может быть гарантирована объявлением. Это приводит к большей безопасности типов за счет гибкости.
Шаблоны - это полные по Тьюрингу (см. метапрограммирование шаблонов ).Обобщения также являются полными по Тьюрингу

Разное

  • Java и C ++ используют разные средства для разделения кода на несколько исходных файлов. Java использует систему пакетов, которая определяет имя файла и путь для всех определений программ. Его компилятор импортирует исполняемые файлы классов. C ++ использует заголовочный файл исходный код систему включения для обмена объявлениями между исходными файлами.
  • Файлы скомпилированного кода Java обычно меньше файлов кода в C ++ как Байт-код Java обычно более компактен, чем собственный машинный код, и программы Java никогда не связываются статически.
  • Компиляция C ++ включает добавленную текстовую фазу предварительной обработки, тогда как Java не. Таким образом, некоторые пользователи добавляют этап предварительной обработки в свой процесс сборки для лучшей поддержки условной компиляции.
  • Операторы деления и модуля в Java четко определены для усечения до нуля. C ++ (pre- C ++ 11 ) не указывает, будут ли эти операторы усекаться до нуля или «усекать до -infinity». -3/2 всегда будет -1 в Java и C ++ 11, но компилятор 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.

Performance

В дополнение к запуску скомпилированной программы Java на компьютерах, на которых выполняются приложения Java, обычно также должна быть запущена виртуальная машина Java (JVM), а скомпилированные программы на C ++ могут запускаться без внешних приложений. Ранние версии Java значительно уступали по производительности статически компилируемым языкам, таким как C ++. Это связано с тем, что операторы программ этих двух тесно связанных языков могут компилироваться в несколько машинных инструкций с помощью C ++, в то же время компилируясь в несколько байтовых кодов, включающих несколько машинных инструкций, каждая при интерпретации JVM. Например:

инструкция Java / C ++сгенерированный код C ++ (x86)сгенерированный Java байт-код
vector [i] ++;
mov edx, [ebp + 4h] mov eax, [ebp + 1Ch] inc dword ptr [edx + eax * 4]
aload_1 iload_2 dup2 iaload iconst_1 iadd iastore

Поскольку оптимизация производительности - очень сложная проблема, очень трудно количественно оценить разница в производительности между C ++ и Java в целом, и большинство тестов ненадежны и необъективны. Учитывая очень разную природу языков, также трудно провести четкие качественные различия. Короче говоря, в Java есть неотъемлемая неэффективность и жесткие ограничения, поскольку она в значительной степени полагается на гибкие высокоуровневые абстракции, однако использование мощного JIT-компилятора (как в современных реализациях JVM) может смягчить некоторые проблемы. В любом случае, если неэффективность Java слишком велика, скомпилированный код C или C ++ может быть вызван из Java через JNI.

Некоторые недостатки, присущие языку Java, включают, в основном:

  • Все объекты размещаются в куче. Несмотря на то, что в современных JVM выделение выполняется очень быстро с использованием «выпуклого выделения», которое работает аналогично выделению стека, производительность все равно может быть снижена из-за вызова сборщика мусора. Современные JIT-компиляторы в некоторой степени смягчают эту проблему с помощью анализа экранирования или обнаружения экранирования для выделения некоторых объектов в стеке, начиная с Oracle JDK 6.
  • В критически важных для производительности проектах, таких как эффективные системы баз данных и библиотеки обмена сообщениями, приходилось использовать внутренние неофициальные API, такие как sun.misc.Unsafeдля получения доступа к ручному управлению ресурсами и возможности выделения стека; эффективное управление псевдо-указателями.
  • Даже при использовании стандартных контейнеров требуется большое количество приведений во время выполнения, что приводит к снижению производительности. Однако большинство этих преобразований статически исключаются JIT-компилятором.
  • Гарантии безопасности связаны с затратами во время выполнения. Например, компилятор должен поставить в код соответствующие проверки диапазона. Защита каждого доступа к массиву с помощью проверки диапазона неэффективна, поэтому большинство JIT-компиляторов попытаются устранить их статически или вывести их из внутренних циклов (хотя большинство собственных компиляторов для C ++ будут делать то же самое, когда необязательно используются проверки диапазона).
  • Отсутствие доступа к низкоуровневым деталям не позволяет разработчику улучшить программу там, где компилятор не может этого сделать.
  • Обязательное использование ссылочной семантики для всех определяемых пользователем типов в Java может создавать большие объемы избыточных обращений к памяти (или переходов) (если их не исключил JIT-компилятор), что может приводить к частым пропускам кеш-памяти (также известное как перегрузка кеша ). Кроме того, оптимизация кеша, обычно с помощью структур данных и алгоритмов с учетом кеша или без учета кеша, часто может приводить к значительному повышению производительности, а также к предотвращению вырождения временной сложности, которое характерно для многих кешей. -пессимизирующие алгоритмы, поэтому это одна из важнейших форм оптимизации; Ссылочная семантика, как предписано в Java, делает такую ​​оптимизацию невозможной на практике (ни программистом, ни JIT-компилятором).
  • Сборка мусора, поскольку эта форма автоматического управления памятью приводит к накладным расходам памяти.

Тем не менее, у дизайна Java есть ряд преимуществ, некоторые из которых были реализованы, некоторые - только теоретически:

  • Java сборка мусора может иметь лучшую согласованность кеша, чем обычное использование malloc / новый для выделения памяти. Тем не менее, существуют аргументы, что оба распределителя одинаково фрагментируют кучу и ни один из них не демонстрирует лучшую локальность кеша. Однако в C ++ выделение отдельных объектов в куче происходит редко, и большие количества отдельных объектов обычно выделяются блоками через контейнер STL и / или с помощью небольшого распределителя объектов.
  • Компиляция во время выполнения может потенциально использовать информацию о платформе, на которой выполняется код, для более эффективного улучшения кода. Однако большинство современных компиляторов (C, C ++ и т. Д.) Генерируют несколько путей кода, чтобы использовать все вычислительные возможности данной системы. Кроме того, можно привести обратный аргумент, что собственные компиляторы могут лучше использовать оптимизацию для конкретной архитектуры и наборы инструкций, чем многоплатформенные дистрибутивы JVM.
  • Компиляция во время выполнения позволяет более агрессивно встраивать виртуальные функции, чем это возможно для статический компилятор, потому что JIT-компилятор имеет больше информации обо всех возможных целях виртуальных вызовов, даже если они находятся в разных динамически загружаемых модулях. Доступные в настоящее время реализации JVM не имеют проблем с встраиванием большинства мономорфных, в основном мономорфных и диморфных вызовов, и в настоящее время ведутся исследования по встраиванию также мегаморфных вызовов, благодаря недавним динамическим улучшениям вызова, добавленным в Java 7. Встраивание может позволить дальнейшую оптимизацию, например векторизация цикла или развертывание цикла, что приводит к огромному увеличению общей производительности.
  • В Java синхронизация потоков встроена в язык, поэтому JIT-компилятор может потенциально, с помощью анализа выхода, снимать блокировки, значительно улучшают производительность наивного многопоточного кода.

Кроме того, в C ++ возникают некоторые проблемы с производительностью:

  • Разрешение указателям указывать на любой адрес может затруднить оптимизацию из-за возможности псевдонима указателя .
  • Поскольку код, сгенерированный из различных экземпляров одного и того же шаблона класса в C ++, не используется совместно (как с универсальными шаблонами со стиранием типов в Java), чрезмерное использование шаблонов может привести к значительному увеличению размер исполняемого кода (раздувание кода ). Однако, поскольку шаблоны функций агрессивно встроены, они иногда могут уменьшить размер кода, но, что более важно, позволяют компилятору проводить более агрессивный статический анализ и оптимизацию кода, что чаще делает их более эффективными, чем код без шаблонов. Напротив, универсальные Java-шаблоны обязательно менее эффективны, чем неуниверсальный код.
  • Поскольку в традиционном компиляторе C ++ динамическое связывание выполняется после генерации и оптимизации кода в C ++, вызовы функций, охватывающие различные динамические модули, не могут быть встроены. Однако современные компиляторы C ++, такие как MSVC и Clang + LLVM, предлагают варианты генерации кода во время компоновки, которые позволяют компилировать модули в промежуточные форматы, что позволяет встраивать их на этапе финальной компоновки.

Официальный стандарт и справочник языка

Спецификация языка

Язык C ++ определен ISO / IEC 14882, стандартом ISO, который опубликован комитетом ISO / IEC JTC1 / SC22 / WG21. Также доступен последний постстандартизационный черновик C ++ 17.

Язык C ++ развивается через открытый руководящий комитет, называемый Комитетом по стандартам C ++. Комитет состоит из создателя C ++ Бьярна Страуструпа, организатора Херба Саттера и других видных деятелей, включая многих представителей отраслей и групп пользователей (т. Е. Заинтересованных сторон).). Поскольку комитет является открытым, любой может свободно присоединяться к нему, участвовать и вносить предложения по предстоящим выпускам стандарта и технических спецификаций. В настоящее время комитет стремится выпускать новый стандарт каждые несколько лет, хотя в прошлом строгие процессы проверки и обсуждения означали более длительные задержки между публикацией новых стандартов (1998, 2003 и 2011).

Язык Java определяется Спецификацией языка

Последняя правка сделана 2021-05-15 08:01:19
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте