Отличия синтаксиса C++ & Java и некоторые особенности Java
В рамках "заметок на полях" - краткий, очень поверхностный и слабо структурированный набор различий в синтаксисе языков C++ и Java, а так же некоторые особенности Java.
- Имя файла исходного кода обязательно должно совпадать с именем класса, чей метод
main()вызывается при запуске Java машины. Object- класс от которого наследуются все объекты в Java, включая массивы и строки (см. таблицу).- Спецификаторы доступа индивидуальны для каждого члена (указываются перед объявлением).
- Все члены класса по умолчанию открыты для области видимости пакета. Область видимости "по умолчанию" - это нечто среднее между
privateиprotected, см. таблицу. - Каждый
*.javaфайл может содержать только один класс объявленный какpublicи доступный извне. - Определение и объявление класса всегда находится в одном файле, невозможно вынести прототипы в заголовки.
- Отсутствуют указатели.
- Все переменные классов - на самом деле ссылки на объекты а не сами объекты. Инициализация их для использования обязательно должна выполняться через
new <конструктор-класса>(...). - Исходя из предыдущего пункта - при присвоении одной переменной-объекта другой выполняется только изменение ссылки но не копирование объекта.
- Переменные в функции передаются по значению если это элементарные типы (int, byte, long, etc...), или по ссылке, если это объекты.
- Доступ к публичным статическим членам класса осуществляется через оператор точки
., а не через::, что на мой взгляд вносит некоторую внешнюю путанницу. - Отсутствует деструктор, но есть
finalize(). - Не стоит путать
finalize()и деструктор С++.finalize()вызывается только при сборке мусора, которая никак не связана с выходом объекта из области видимости и отсутствием хотя бы одной ссылки на данный объект. - Сборку мусора можно форсировать вызвав метод
Runtime.gc()на текущем объектеRuntimeили статический методSystem.gc(). Судя по проведённым опытам - освобождение памяти работает только в пределах виртуальной машины Java и однажды выделенную память в ОС не возвращает пока не завершится машина. - В Java-стиле написания кода функции генерируют исключения, вместо возврата кода системной ошибки или ошибки логики виртуальной машины. Потому множество функций обязательно должно выполняться внутри блока
try { ... } catch (...) { ... }обрабатывающего исключения, либо метод вызывающий их должен явно указывать черезthrowsсписок не обрабатываемых им исключений генерируемых этими функциями, для обработки их методами "выше" по стеку вызовов. - Исключения делятся на непроверяемые и проверяемые.
- Блок
try { ... }также может заканчиваться блокомfinally { ... }, выполняющемся независимо от наличия/отсутствия исключений в предыдущем блокеtry { ... }. Это удобно использовать для выполнения каких-либо обязательных действий независимо от результатов выполнения блока кода, например для автоматического освобождения всех выделенных в нём ресурсов. charэто не однобайтный тип как с С/С++, это 16-битный тип поддерживающий unicode строки.boolв Java известен какboolean.- Условные конструкции принимают только
booleanтип переменных или выражений. Это значит что код вида:
int a; ... действия над переменной a ...; if(a) { ... }
Не верен с точки зрения Java синтаксиса и не будет скомпилирован. - Константы объявляются словом
finalа неconst. - Все массивы - объекты.
- Даже строковые константы (например
"any string const") являются объектами. - Для строк (класс
String) определён только один оператор -+, конкатенация. - Сравнение строк выполняется через метод
bool equals()классаString, напримерs1.equals(s2). - Содержимое объектов-строк (
String) константно и не подразумевает изменения отдельного элемента строки, это сделано в целях повышения производительности. При необходимости подобных операций можно использовать классStringBuffer. - При конкатенации не инициализированной строки с не пустой строкой получится null + не-пустая-строка, например
s += "|string";будет равно"null|string" - Массивы имеют переменную-член с публичным доступом
length, строки не имеют, вместо этого в них используется методlength(). - Java не поддерживает множественного наследования. Отчасти его функции выполняются через "интерфейсы" (
interface). Интерфейсы поддерживают множественное "наследование"-реализацию (implements) нескольких интерфейсов в одном классе, и в целом отношения "многие (интерфейсы) ко многим (классам)" и наоборот. - Интерфейсы допускают создание ссылок через которые можно обращаться к объектам классов реализующих эти интерфейсы. Правда динамический поиск подходящего метода при обращении через ссылку-интерфейс требует много накладных расходов, потому не желателен.
- Вместо перечислений
enumможно использовать интерфейсы без объявлений методов в них. В таком случае все переменные интерфейса должны быть инициализированны при определении интерфейса и их значения автоматически будут константны. После этого, черезimplementsих можно "подключать" в определяемый класс. - Так же, начиная с JDK 5 существуют внешне классические перечисления -
enum. На самом деле это не просто список именованных констант, а специальный класс наследуемый от суперклассаEnum. Каждый элемент перечисления - объект этого класса. Числовое значение объекта перечисления можно получить встроенной функциейordinal. - Пользовательсякая перегрузка операторов привычная в С++, в Java не поддерживается.
- Для работы в объектной среде с "примитивными типами" (int, float, char, etc...) в Java используется автоупаковка/автораспаковка в типы-оболочки (Integer, Float, Character, etc...). По сути это реализация перегрузки операторов для нескольких встроенных классов реализующих функционал примитивных типов + объектные методы.
super- ключевое слов опозволяющее вызвать конструктор суперкласса из подкласса, либо обратиться к члену суперкласса скрытого членом подкласса.- В случае использования в качестве конструктора -
superвсегда должен быть первым оператором в конструкторе подкласса.
- В случае использования в качестве конструктора -
- Для определения абстрактных методов используется ключевое слово
abstract, класс содержащий абстрактный метод так же должен определяться какabstract class .... finalзапрещает переопределять методы в дочерних классах. Для "коротких" методов объявленных какfinal, это ключевое слово оказывает эффект аналогичныйinlineв С++ - в подклассах вместо вызова функции может быть вставлен байт-код метода суперкласса в код метода вызывающего класса.finalтакже запрещает наследовать класс объявленный какfinal.- Пространства имён (
namespace) в Java реализуются как пакеты (package). - Для подключения пакетов используется
import, так же можно использоватьimport static <package-name>.<class-name>.(*|<member-name>)для импорта статических членов класса. - Java поддерживает потоки через встроенный класс
Threadи интерфейсRunable. Для синхронизации используется спецификаторsynchronizedперед методом в описании класса, илиsynchronized(<object>) { ... }для блока кода синхронизируемого с<object>. Для сигналов между синхронизированными потоками используются методы родительского класса Object:wait()/notify()/notifyAll(). transient- модификатор сообщающий что значение объекта/переменной не нужно "удерживать" при сохранении объекта, например при сериализации его перед записью на диск/в БД. Логично таким образом помечать переменные содержащие уникальные идентификаторы времени выполнения и прочую подобную информацию имеющую смысл только в текущем экземпляре java-процесса.<object> instanceof <type>- операция времени выполнения, возвращает true если<object>есть ссылка на класс<type>, либо может быть приведён к ссылке на этот класс, иначе false.assert- утверждения в Java используются примерно так же как и в С:assert <bool expression> [: Assertion fail description], но нужно иметь ввиду что они "вшиваются" в скомпилированный байт-код, и могут быть включены при запускеjava -ea.this(...)- может быть использовано внутри конструктора класса для вызова другого конструктора этого же класса, подходящего по сигнатуре аргументов.- Вместо шаблонов используются обобщения, внешне очень похоже:
class CLASS_NAME<type-name[, type-name2, ...]> { ... }. В обобщениях нельзя использовать примитивные типы (int, byte, char, etc...). В качестве параметров могут быть использованы только классы.
Кроме того, поддерживаются ограниченные типы, через указание суперкласса для классов-параметров. Например, объявление "обобщённого класса"class CLASS_NAME<T extends Number>в котором допустимо использовать только классы-потомки общего класса числовыхNumber. - Для быстрого копирования массивов удобно применять
System.arraycopy().

