Отличия синтаксиса 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()
.