Дублирование ссылок и клонирование
Из-за того, что объектные переменные являются ссылочными, при присваивании не происходит копирования объекта. Так, если написать
Foo foo, bar;…bar = foo;то произойдет копирование адреса из переменной foo в переменную bar. То есть foo и bar будут указывать на одну и ту же область памяти, то есть на один и тот же объект; попытка изменить поля объекта, на который ссылается переменная foo, будет менять объект, с которым связана переменная bar, и наоборот. Если же необходимо получить именно ещё однукопию исходного объекта, пользуются или методом (функцией-членом, в терминологии C++) clone(), создающим копию объекта, или (реже) копирующим конструктором(конструкторы в Java не могут быть виртуальными, поэтому экземпляр класса-потомка будет неправильно скопирован конструктором класса-предка; метод клонирования вызывает нужный конструктор и тем самым позволяет обойти это ограничение).
Метод clone() требует, чтобы класс реализовывал интерфейс Cloneable (об интерфейсах см. ниже). Если класс реализует интерфейс Cloneable, по умолчанию clone() копирует все поля (мелкая копия). Если требуется не копировать, а клонировать поля (а также их поля и так далее), надо переопределять метод clone(). Определение и использование методаclone() часто является нетривиальной задачей.
Сборка мусора
В языке Java невозможно явное удаление объекта из памяти — вместо этого реализована сборка мусора. Традиционным приёмом, дающим сборщику мусора «намёк» на освобождение памяти, является присваивание переменной пустого значения null. Это, однако, не значит, что объект, заменённый значением null, будет непременно и немедленно удалён, но есть гарантия, что этот объект будет удалён именно в будущем. Данный приём всего лишь устраняет ссылку на объект, то есть отвязывает указатель от объекта в памяти. При этом следует учитывать, что объект не будет удален сборщиком мусора, пока на него указывает хотя бы одна ссылка из используемых переменных или объектов. Существуют также методы для инициации принудительной сборки мусора, но не гарантируется, что они будут вызваны исполняющей средой, и их не рекомендуется использовать для обычной работы.
Классы и функции
Java не является процедурным языком: любая функция может существовать только внутри класса. Это подчёркивает терминология языка Java, где нет понятий «функция» или «функция-член» (англ. member function), а только метод. В методы превратились и стандартные функции. Например, в Java нет функции sin(), а есть метод Math.sin() класса Math(содержащего, кроме sin(), методы cos(), exp(), sqrt(), abs() и многие другие). Конструкторы в Java не считаются методами. Деструкторов в Java не существует, а метод finalize() ни в коем случае нельзя считать аналогом деструктора.
Статические методы и поля
В Java (как и в C++) используются статические методы (англ. static method — в теории программирования их также называют методами класса), которые задаются при помощи ключевого слова static. Статические поля (переменные класса) имеют тот же смысл, что и в C++: каждое такое поле является собственностью класса, поэтому для доступа к статическим полям не требуется создавать экземпляры соответствующего класса.
Например, математические функции, реализованные в классе Math, представляют собой как раз статические методы данного класса. Поэтому можно писать
double x =Math.sin(1);вместо
Math m =newMath();double x = m.sin(1);Поскольку статические методы существуют независимо от объектов (экземпляров класса), они не имеют доступа к обычным (нестатическим) полям и методам данного класса. В частности, при реализации статического метода недопустимо использовать идентификатор this.
Завершённость (final)
Ключевое слово final (финальный) означает разные вещи при описании поля, метода или класса. Финальное поле класса инициализируется при описании, или в конструкторе класса (а статическое поле — в статическом блоке инициализации) и дальше его значение не может быть изменено. Значения локальных переменных, а также параметров метода, помеченных ключевым словом final, не могут быть изменены после присвоения. Но при этом, их значения могут использоваться внутри анонимных классов. Если статичное поле класса, или переменная проинициализированны константным выражением, они рассматриваются компилятором, как именованная константа; в таком случае их значение может быть использовано воператорах switch (для констант типа int), а также для условной компиляции (для констант типа boolean) при использовании с оператором if.
Метод класса, отмеченный словом final, не может быть переопределён при наследовании. Финальный класс не может иметь наследников вообще.
Абстрактность
В Java методы, не объявленные явно как static, final или private, являются виртуальными в терминологии C++: при вызове метода, по-разному определённого в базовом и наследующем классах, всегда производится проверка времени выполнения.
Абстрактным методом (модификатор abstract) в Java называется метод, для которого заданы параметры и тип возвращаемого значения, но не тело. Абстрактный метод определяется в классах-наследниках. В C++ то же самое называется чистой виртуальной функцией (pure). Для того чтобы в классе можно было описывать абстрактные методы, сам класс тоже должен быть описан как абстрактный. Объекты абстрактного класса создавать нельзя.
Интерфейсы
Высшей степенью абстрактности в Java является интерфейс (interface). Все методы интерфейса абстрактны: описатель abstract даже не требуется. Интерфейс в Java не считается классом, хотя по сути является полностью абстрактным классом. Класс может наследовать/расширять (extends) другой класс или реализовывать (implements) интерфейс. Кроме того, интерфейс может наследовать/расширять другой интерфейс.
В Java класс не может наследовать более одного класса, зато может реализовывать сколько угодно интерфейсов. Множественное наследование интерфейсов не запрещено, то есть один интерфейс может наследоваться от нескольких.
Интерфейсы можно передавать методам как параметры, но нельзя создавать экземпляры интерфейсов.
Маркерные интерфейсы
В Java есть некоторые интерфейсы, которые не содержат методов для реализации, а специальным образом обрабатываются JVM. Это интерфейсы:
· java.lang.Cloneable
· java.io.Serializable
· java.rmi.Remote
Шаблоны в Java (generics)
Начиная с версии Java 5 в языке появился механизм обобщённого программирования — шаблоны, внешне близкие к шаблонам C++. С помощью специального синтаксиса в описании классов и методов можно указать параметры-типы, которые внутри описания могут использоваться в качестве типов полей, параметров и возвращаемых значений методов.
// Объявление обобщённого классаclass GenericClass<E>{ E getFirst(){ ... }voidadd(Eobj){ ... }} // Использование обобщённого класса в кодеGenericClass<String> var =new GenericClass<String>();var.add("qwerty");String p =var.getFirst();Допускается обобщённое объявление классов, интерфейсов и методов. Кроме того, синтаксис поддерживает ограниченные объявления типов-параметров: указание в объявлении конструкции вида <T extends A & B & C...> требует, чтобы тип-параметр T реализовывал интерфейсы A, B, C и так далее, а конструкция <T super C> требует, чтобы тип-параметр T был типом C или одним из его предков.
В отличие от шаблонов C#, шаблоны Java не поддерживаются средой исполнения — компилятор просто создаёт байт-код, в котором никаких шаблонов уже нет. Реализация шаблонов в Java принципиально отличается от реализации аналогичных механизмов в C++: компилятор не порождает для каждого случая использования шаблона отдельный вариант класса или метода-шаблона, а просто создаёт одну реализацию байт-кода, содержащую необходимые проверки и преобразования типов. Это приводит к ряду ограничений использования шаблонов в программах на Java.