Public boolean equals(Object obj)
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Проверяет, равны ли текущий объект и объект, на который указывает ссылка obj, переданная в качестве параметра, и возвращает значение true, если факт равенства установлен, и false – в противном случае. Если необходимо проверить, указывают ли две ссылки на один и тот же объект, следует применять операторы == или !=. Метод equals сопоставляет содержимое объектов. В исходной реализации метода equals, предусмотренной в классе Object, предполагается, что объект равен только самому себе, т.е.удовлетворяет условию this ==obj.

Public int hashCode ()

Возвращает значение хеш-кода (hash code) текущего объекта – числа, используемого для быстрого сравнения объектов. Каждый объект обладает собственным хеш-кодом, который находит применение в хеш-таблицах. В реализации по умолчанию предусмотрен возврат значения, которое, как правило, различно для разных объектов. Значение кода используется в процессе сохранения объекта в одной из хеш-коллекций. Если объект не изменял свое состояние, то значение хэш-кода не должно изменяться

Protected Object clone() throws CloneNotSupportedException

Возвращает клон текущего объекта. Клон – это новый объект, являющийся копией текущего.

Public final Class getClass()

Возвращает объект типа Class, который представляет информацию о классе текущего объекта на этапе выполнения программы.

Protected void finalize() throws Throwable

Позволяет выполнить необходимые операции очистки состояния объекта до того момента, когда объект будет уничтожен в процессе сборки мусора.

Public String toString()

Возвращает строковое представление объекта. Метод toString вызывается неявно, когда ссылка на объект употребляется в качестве операнда в контексте выражений конкатенации строк с помощью оператора +. Версия метода toString, реализованная в классе Object, по умолчанию возвращает строку, содержащую наименование класса, которому принадлежит текущий объект, символ @ и шестнадцатеричное представление хеш-кода объекта.

Оба метода, hashCode и equals, должны быть переопределены, если необходимо придать понятию равенства объектов иной смысл, отличный от того, который предлагается классом Object. По умолчанию считается, что любые два различных объекта «не равны», т.е. метод equals возвращает значение false, и их хеш-коды, как правило, различны.

Если версия метода equals, реализованная в некоем классе, допускает «равенство» двух различных объектов, их хеш-коды, возвращаемые соответствующими вариантами метода hashCode, также должны быть равны. Если хэш-коды объектов одинаковы, то это еще не значит, что объекты эквивалентны. Механизм хеширования тесно связан с методом equals, возвращающим true, если в хеш-таблице найден ключ с заданным значением. Изменение реализации в классе метода equals() влечет за собой изменение реализации метода hashCode(). Например, в классе String метод equals переопределен таким образом, что он возвращает true, если оба сопоставляемых объекта String обладают одинаковым содержимым. В классе String также переопределен и метод hashCode – он возвращает значение, непосредственно зависящее от содержимого строки, так что две одинаковые строки неизбежно будут иметь один и тот же хеш-код.

Клонирование объектов

Результатом клонирования является копия объекта. Массивы поддерживают операцию клонирования:

int[] arrayCopy = (int []) array.clone();

В классе Object метод clone() является защищенным. Метод clone() реализуется в конкретном классе. Никто не гарантирует того, что результатом его выполнения будет копия объекта, и даже того, что новый объект будет того же класса. Однако существует ряд соглашений, регламентирующих реализацию метода clone():

· Класс должен реализовывать интерфейс-маркер (пустой интерфейс) Cloneable. Метод Object.clone() проверяет, реализован ли в классе, которому принадлежит текущий объект, интерфейc Cloneable, и выбрасывает исключение типа CloneNotSupportedException, если ответ отрицательный.

· Класс должен переопределять метод clone(). Результатом работы метода Object.clone() является точная копия объекта, т.е. Object.clone() обеспечивает простое клонирование - копирование всех полей исходного объекта в объект-копию и по завершении работы возвращается ссылка на созданный объект-копию. Метод вполне работоспособен во многих ситуациях, но при определённых обстоятельствах приходится его переопределять и дополнять.

· Результат клонирования должен быть получен вызовом super.clone().

public Object clone() {

Object result = null;

  try {

   result = super.clone();

} catch (CloneNotSupportedException ex) { }

return result;

}

Простого клонирования может быть недостаточно, в этом случае применяется глубокое клонирование. В процессе глубокого клонирования соответствующие методы clone вызываются для каждого объекта, обозначенного переменной-полем, и каждого элемента массива объектов. Процесс носит рекурсивный характер – клонированию подвергаются все объекты, служащие членами других объектов, начиная от текущего. Т.е. если объект содержит ссылки на агрегированные объекты, после процедуры простого клонирования необходимо создать и их копии тоже.

public Object clone() {

Object result = null;

try {

result = super.clone();

result.a = (...) a.clone();

...

} catch (CloneNotSupportedException ex) { }

return result;

}

Интерфейсы

Базовая единица программы, написанной на языке Java – это класс ( class ), но базовый инструмент ООП – это тип ( type ). Посредством классов определяются типы, но иногда полезно иметь возможность определять типы без необходимости объявления классов. Интерфейс (interface) позволяет описать тип в абстрактной форме – в виде набора заголовков методов и объявлений констант, которые образуют контракт типа. Интерфейс не содержит блоков реализации – его экземпляры создавать нельзя. Эта возможность предоставляется производным классам, которые способны реализовать (implements) один или несколько интерфейсов. Интерфейс – это образец чистой формы, а класс – сочетание формы (дизайна) и содержания (реализации). Каждый более или менее серьёзный класс приложения Java , как правило, реализует какие-либо интерфейсы, которые определяют основные «очертания» контракта класса.

Класс способен реализовать более одного интерфейса. Язык программирования Java допускает возможность множественного наследования интерфейсов и единичного наследования реализации – классу позволено непосредственно наследовать только один базовый класс.

Все классы, которые расширяются конкретным классом, и все реализуемые им интерфейсы в совокупности называют базовыми типами (supertypes). Новый класс – с точки зрения базовых типов – принято называть производный тип (subtype). Производный тип есть любой из унаследованных им базовых типов, поэтому ссылка на объект производного типа может быть полиморфным образом использована в любом контексте, где требуется ссылка на любой из базовых типов (класс или интерфейс). Объявление интерфейса создаёт новый тип точно так же, как и объявление класса. Наименование интерфейса можно употреблять в качестве имени типа в объявлении любой переменной – и такой переменной допускается присваивать ссылки на объекты соответствующих производных типов.

Пример простого интерфейса

Некий простой интерфейс часто определяет свойство, присущее множеству объектов самых разнообразных классов. Подобные свойства нередко выражают в терминах способности (“ ability ”) объекта выполнять определённые функции. Например, в составе стандартных пакетов Java есть немало интерфейсов, в названии которых присутствует характерный суффикс “ able ”.

· Cloneable. Объекты этого типа поддерживают операцию клонирования.

· Comparable. Объекты Comparable допускают упорядочение и поэтому могут сравниваться.

· Runnable. Соответствующие объекты содержат код, способный выполняться в виде независимого потока вычислений.

· Serializable. Объекты этого типа могут быть преобразованы в последовательность байтов с целью сохранения на носителях или переноса в среду другой виртуальной машины, а затем при необходимости восстановлены в исходном «живом» виде.

Рассмотрим в качестве примера интерфейс Comparable. Этот интерфейс может быть реализован в любом классе, объекты которого поддерживают некий «естественный порядок». Интерфейс содержит единственный метод и выглядит следующим образом:

Пример 28.

public interface Comparable {

int compareTo ( Object o );

}

Объявление интерфейса сродни объявлению класса за тем исключением, что вместо служебного слова class используется слово interface . Помимо этого существуют определённые правила объявления членов интерфейса, о которых будет сказано чуть позже.

Метод compareTo в качестве аргумента принимает ссылку на объект типа Object и сравнивает его с текущим объектом, возвращая отрицательное, положительное или нулевое целое число, если, соответственно, текущий объект меньше или больше аргумента, или равен ему. Если два объекта взаимно несопоставимы (обычно вследствие несовместимости их типов, например, Integer заведомо нельзя сравнивать со String ), выбрасывается исключение типа ClassCastException .

Вспомним класс, служащий для представления данных о небесных телах. Естественный порядок тел, являющихся спутниками одного и того же «центрального» светила, может быть определён в зависимости от радиуса орбиты их вращения. Соответствующая версия объявления класса Body будет выглядеть, например, так (см. пример 29):

Пример 29.

class Body implements Comparable {

// Объявления полей опущены

int orbitalDistance = …; // Задаётся в процессе конструирования

public int compareTo(Object o) {

     Body other = (Body)o;

     if (orbits == other.orbits)

          return orbitalDistance – other.orbitalDistance;

     else

         throw new IllegalArgumentException(" Неверное значение orbits");

}

}

Первым делом мы отмечаем тот факт, что Body – это сопоставимый ( Comparable ) тип. Интерфейсные типы, реализуемые классом, в его объявлении перечисляются после служебного слова implements (конструкция implements целиком размещается после предложения extends, если таковое имеется, но перед блоком тела класса). Все указанные в объявлении интерфейсы называют базовыми интерфейсами (superinterfaces) класса. Класс обязан обеспечить реализацию всех методов, определённых в унаследованных базовых интерфейсах, иначе в его объявление следует включить модификатор abstract, имея в виду, что конкретной реализацией в будущем «займутся» какие-либо конкретные (неабстрактные) производные классы.

В примере класса Body (примере 29), как и во многих других возможных реализациях метода compareTo , используетя оператор явного преобразования типов, который заменяет ссылку на объект Object ссылкой на объект класса Body . Преобразование типов осуществляется перед операцией сравнения. Если ссылка, переданная в качестве аргумента, указывает на объект, не относящийся к классу Body и поэтому не поддерживающий подобное преобразование, генерируется исключение типа ClassCastException . Затем вычисляется разность радиусов орбит двух тел и возвращается результат. Если тела не являются спутниками одного и того же «центрального» небесного объекта, они не могут быть сопоставлены, и поэтому выбрасывается исключение типа IllegalArgumentException .

Интерфейсы, как и классы, вводят в обиход новые наименования типов, которые могут быть использованы в объявлениях переменных:

Comparable obj ;

Действительно, мощь интерфейсов во многом обусловлена именно тем обстоятельством, что зачастую вместо переменных конкретных типов гораздо удобнее и выгоднее объявлять переменные соответствующих интерфейсных типов. Например, целесообразно определить общий метод сортировки таким образом, чтобы он оказался способен сортировать элементы любого массива объектов типа Comparable (разумеется, объекты должны быть сопоставимы), независимо от того, какому конкретному классу они принадлежат:

Пример 30.

class Sorter {

public static Comparable[] sort(Comparable[] list){

    // Детали реализации…

    return list ;

    }

}

Посредством ссылки на интерфейсный тип, однако, разрешается обращаться только к членам соответствующего интерфейса. Например, следующий фрагмент кода породит ошибку компиляции (пример 31):

Пример 31.

Comparable obj = new Body ();

String name = obj.getName(); // Неверно :

// в составе интерфейса Comparable нет метода getName

Если необходимо интерпретировать obj как объект класса Body, следует применить соответствующий оператор преобразования типов. Существует, правда, единственное исключение из этого правила: ссылку на любой интерфейс позволяется трактовать как ссылку на объект класса Object, поскольку Object – это базовый класс по отношению ко всем классам и интерфейсам. Поэтому следующее выражение вполне допустимо:

String desc = obj . toString ();

Здесь ссылка на интерфейсный тип Comparable неявно преобразуется в ссылку на тип Object.

Объявление интерфейса

В объявлении интерфейса содержится служебное слово interface , за которым следует наименование интерфейса и перечень его членов, заключенный в фигурные скобки.

В составе интерфейса могут присутствовать члены трёх категорий:

· константы (поля);

· методы;

· вложенные классы и интерфейсы.

Все члены интерфейса по умолчанию обладают признаком public, но модификатор public принято опускать. Применение других модификаторов доступа по отношению к членам интерфейса лишено особого смысла.

Константы в интерфейсах

В состав интерфейса могут быть включены объявления именованных констант. Такие константы определяются как поля, но им неявно присваиваются признаки public, static и final – и вновь, по традиции, соответствующие модификаторы принято не указывать. Поля должны быть снабжены соответствующими инициализаторами – использование полей вида blank final не разрешается.

Поскольку в объявлении интерфейса отсутствует какой-либо код реализации, здесь запрещено объявление «нормальных» полей – в противном случае они послужили бы частью контракта интерфейса, которая «диктовала» бы производным классам те или иные правила реализации, а это противоречит самой сути интерфейса. Тем не менее, в интерфейсах позволено определять именованные константы, поскольку подчас они бывают весьма полезны при проектировании типов. Например, объявление интерфейса, описывающего возможные уровни красноречия человека, могло бы выглядеть так (пример 32):

Пример 32.

interface Verbose {

int SILENT  = 0; // Безмолвный

int TERSE    = 1; // Немногословный

int NORM    = 2; // Нормальный

int VERVOSE = 3; // Многоречивый

void setVerbosity(int level);

int getVerbosity();

}

В метод setVerbosity вместо « безмолвных » чисел удобнее передавать « красноречивые » константы SILENT, TERSE, NORM или VERVOSE, смысл которых определён в самих их названиях .

Если интерфейс должен содержать данные, поддающиеся изменению и позволяющие совместное использование, этого можно добиться, применяя именованные константы, которые ссылаются на объекты с необходимыми полями данных. Для создания такого рода объектов уместно использовать вложенные классы, которые будут рассмотрены далее.

Методы в интерфейсах

Методы, объявляемые в составе интерфейса, неявно получают признак abstract, поскольку не содержат (и не могут содержать) блок тела. По этой причине блок тела в объявлении заменяется символом точки с запятой. В соответствии с принятым соглашением модификатор abstract в объявлении метода не указывается.

В объявлении метода, принадлежащего интерфейсу, запрещается задавать и какие-либо другие модификаторы. Все методы неявно помечаются признаком public , поэтому использование других модификаторов доступа не допускается ( public также обычно исключается). В объявлениях методов нельзя употреблять модификаторы, имеющие отношение к особенностям реализации – такие как native , synchronized или strictfp , - поскольку интерфейс по определению не способен регламентировать правила реализации. Методы запрещено помечать признаком final , так как в их объявлениях вообще отсутствуют какие-либо блоки реализации, которые можно было бы трактовать как «финальные». Кроме того, методы интерфейсов не способны быть статическими, поскольку модификаторы static и abstract нельзя использовать одновременно. Разумеется, внутри объявлений классов, реализующих интерфейс, те же (переопределённые) методы могут быть снабжены любыми подходящими модификаторами.

Дата: 2019-02-19, просмотров: 260.