Java Урок 42: Класс Object, методы класса object
В Java определен один специальный класс — Object. Все остальные классы
являются подклассами этого класса. То есть Object — суперкласс всех остальных классов.
Скачать исходники для статьи можно ниже
Это означает, что ссылочная переменная класса Object может ссылаться
на объект любого другого класса. Кроме того, поскольку массивы реализованы в виде классов, переменная класса Object может ссылаться также на любой массив.
Класс Object определяет некоторые методы, которые доступны в любом объекте:
1.Object clone() – Создает новый объект, не отличающийся от клонируемого
2.boolean equals(Object object) – Определяет, равен ли один объект другому
3.void finalize() – Вызывается перед удалением неиспользуемого объекта
4.Class> getClass() – Получает класс объекта во время выполнения
5.int hashCode() – Возвращает хеш-код, связанный с вызывающим объектом
6.void notify() – Возобновляет выполнение потока
7.void notifyAll() – Возобновляет выполнение всех потоков
8.String toString() – Возвращает строку, которая описывает объект
9.void wait() – Ожидает другого потока выполнения
10.void wait(long миллисек) – Ожидает другого потока выполнения
11.void wait(long миллисек,int наносек) – Ожидает другого потока выполнения
Методы getClass(), notify(), notifyAll() и wait() объявлены как final.
Остальные методы можно переопределять.
Обратите внимание на два метода: equals() и toString().
Метод equals() сравнивает два объекта. Если объекты равны, он возвращает значение true, если нет — false. Точное определение равенства зависит от типа сравниваемых объектов.
Метод toString() возвращает строку, которая содержит описание объекта,
по отношению к которому он вызван. Кроме того, этот метод автоматически вызывается при выводе объекта с помощью метода println().
Многие классы переопределяют этот метод. Это позволяет им приспосабливать описание специально для создаваемых ими объектных типов.
mnogoblog.ru
Ответы на вопросы для собеседования по Java SE (Часть 1)
В сети распространены различные варианты вопросов на собеседование по Java SE6. Но ответов на эти вопросы нет. Подумав, я решил, что это очень интересная тема для поста и дальнейшего обсуждения. И поэтому начинается цикл статей, посвященный ответам на вопросы по Java Core. За основу я взял 50 вопросов для интервьюирования.
Итак первые 5 вопросов с моими вариантами ответов:
1. Что такое класс Object? Какие в нем есть методы?
Object это базовый класс для всех остальных объектов в Java. Каждый класс наследуется от Object. Соответственно все классы наследуют методы класса Object.
Методы класса Object:
- public final native Class getClass()
- public native int hashCode()
- public boolean equals(Object obj)
- protected native Object clone() throws CloneNotSupportedException
- public String toString()
- public final native void notify()
- public final native void notifyAll()
- public final native void wait(long timeout) throws InterruptedException
- public final void wait(long timeout, int nanos) throws InterruptedException
- public final void wait() throws InterruptedException
- protected void finalize() throws Throwable
2. Что такое метод equals(). Чем он отличается от операции ==.
Метод equals() обозначает отношение эквивалентности объектов. Эквивалентным называется отношение, которое является симметричным, транзитивным и рефлексивным.
- Рефлексивность: для любого ненулевого x, x.equals(x) вернет true;
- Транзитивность: для любого ненулевого x, y и z, если x.equals(y) и y.eqals(z) вернет true, тогда и x.equals(z) вернет true;
- Симметричность: для любого ненулевого x и y, x.equals(y) должно вернуть true, тогда и только тогда, когда y.equals(x) вернет true.
x
, x.equals(null)
должно вернуть false.Отличия equals() от операции == в классе Object нет. Это видно, если взглянуть исходный код метода equals класса Object:
Однако, нужно не забывать, что, если объект ни на что не ссылается(null), то вызов метода equals этого объекта приведет к NullPointerException. Также нужно помнить, что при сравнении объектов оба они могут быть null и операция obj1 == obj2 в данном случае будет true, а вызов equals приведет к исключению NullPointerException.
Понятно, что тут уже нет сравнения ссылок, а сравниваются int значения.
3. Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода?
Эти условия приведены в пункте 2.
4. Если equals() переопределен, есть ли какие-либо другие методы, которые следует переопределить?
Да, есть.Нужно переопределить метод hashCode(). Равные объекты должны возвращать одинаковые хэш коды. Например у класса Integer метод hashCode() переопределен следующим образом:
public int hashCode() {
return value;
}Syhi-подсветка кодаvalue это private значение, которое хранит объект класса Integer. Собственно это и есть число.5. Для чего нужен метод hashCode()?
Для начала вспомним, что такое хэш и хэширование. Теперь вспоминаем такие известные классы, как HashMap, HashSet, Hashtable, в основе которых лежит вычисление хэш-функции. Именно за счет хэша мы можем вставлять и получать данные за O(1), то есть за время пропорциональное вычислению хэш-функции.
public V put(K key, V value) {
...
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
...
addEntry(hash, key, value, i);
...
}Syhi-подсветка кодаКак мы видим, i-е место вставки объекта вычисляется при помощи хэша. А для вычисления нам нужна хорошая хэш функция, чтобы давала равномерное распределение и поменьше коллизий.
То есть ответ на вопрос заключается в том, что существуют коллекции(HashMap, HashSet), которые используют хэш код, как основу при работе с объектами. А если хэш для равных объектов будет разным, то в HashMap будут два равных значения, что является ошибкой. Поэтому необходимо соответствующим образом переопределить метод hashCode().
Пока, что всё. Впереди нас ждет много интересных вопросов!
До встречи.
Продолжение:
Ответы на вопросы для собеседования по Java SE (Часть 2)
dr-magic.blogspot.com
Перегрузка методов equals() и hashCode() в Java
Переопределение методов equals() и hashCode() в Java
Equals
и hashCode
являются фундаментальными методами объявленные в классе Object
и содержатся в стандартных библиотеках Java. Метод еquals()
используется для сравнения объектов, а hashCode
- для генерации целочисленного кода объекта. Эти методы широко используются в стандартных библиотеках Java при вставке и извлечению объектов в HashMap
. Метод equal
также используется для обеспечения хранения только уникальных объектов в HashSet
и других Set
реализациях, а также в любых других случаях, когда нужно сравнивать объекты. Реализация по умолчанию метода equals()
в классе java.lang.Object
сравнивает ссылки на адреса в памяти, которые хранят переменные, и возвращает true
только в том случае, если адреса совпадают, другими словами переменные ссылаются на один и тот же объект. Java рекомендует переопределять методы
equals()
и hashCode()
, если предполагается, что сравнение должно осуществляться в соответсвии с естественной логикой или бизнес-логикой. Многие классы в стандартных библиотеках Java переопределяет их, например в классе String
переопределяется equals
таким образом, что возвращается true
, если содержимое двух сравниваемых объектов одинаковое. В классе-обертке Integer
метод equal
переопределяется для выполнения численного сравнения, и так далее.

HashMap
и HashTable
в Java полагаются на методы equals()
и hashCode()
для сравнения своих key
и values
, то Java предлагает следующие правила для переопределения этих методов:
- Рефлексивность: Объект должен равняться себе самому.
- Симметричность: если
a.equals(b)
возвращаетtrue
, тоb.equals(a)
должен тоже вернутьtrue
. - Транзитивность: если
a.equals(b)
возвращаетtrue
иb.equals(c)
тоже возвращаетtrue
, тоc.equals(a)
тоже должен возвращатьtrue
. - Согласованность: повторный вызов метода
equals()
должен возвращать одно и тоже значение до тех пор, пока какое-либо значение свойств объекта не будет изменено. То есть, если два объекта равны в Java, то они будут равны пока их свойства остаются неизменными. - Сравнение
null
: объект должны быть проверен наnull
. Если объект равенnull
, то метод должен вернутьfalse
, а неNullPointerException
. Например,a.equals(null)
должен вернутьfalse
.
Соглашение между equals и hashCode в Java.
- Если объекты равны по результатам выполнения метода
equals
, тогда ихhashcode
должны быть одинаковыми. - Если объекты не равны по результатам выполнения метода
equals
, тогда ихhashcode
могут быть как одинаковыми, так и разными. Однако для повышения производительности, лучше, чтобы разные объекты возвращали разные коды.
Как переопределять метод equals в Java
-
@Override public boolean equals(Object obj) { if (obj == this) { return true; }
Проверьте объект на
null
, а также проверьте, чтобы объекты были одного типа. Не делайте проверку с помощьюinstanceof
так как такая проверка будет возвращатьtrue
для подклассов и будет работать правильно только в случае если ваш класс объявлен какimmutable
. Вместо этого можно использоватьgetClass()
;if (obj == null || obj.getClass() != this.getClass()) { return false; }
Объявите переменную типа, который вы сравниваете, и приведите
obj
к этому типу. Потом сравнивайте каждый атрибут типа начиная с численных атрибутов (если имеются) потому что численные атрибуты проверяются быстрей. Сравнивайте атрибуты с помощью операторов И и ИЛИ (так называемыеshort-circuit logical operators
) для объединения проверок с другими атрибутами.Person guest = (Person) obj; return id == guest.id && (firstName == guest.firstName || (firstName != null && firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName || (lastName != null && lastName .equals(guest.getLastName()))); }
public class Person { private int id; private String firstName; private String lastName; public int getId() { return id; } public void setId(int id) { this.id = id;} public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj == null || obj.getClass() != this.getClass()) { return false; } Person guest = (Person) obj; return id == guest.id && (firstName == guest.firstName || (firstName != null &&firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName || (lastName != null && lastName .equals(guest.getLastName()) )); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); result = prime * result + id; result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); return result; } }
Распространенные ошибки при переопределении equals в Java
- Вместо того, чтобы переопределять метод
equals (Override)
программист перегружает его(Overload)
Синтаксис методаequals()
в классеObject
определен какpublic boolean equals(Object obj)
, но многие программисты ненароком перегружают метод:public boolean equals(Person obj)
- вместоObject
в качестве аргумента используют имя своего класса (напр. Person). Эту ошибку сложно обнаружить из-заstatic binding
. Таким образом, если вы вызовите этот метод для объекта своего класса, то метод не просто скомпелируется, а даже сделает это корректно. Однако, если вы положите ваш объект в коллекцию, напримерArrayList
и вызовите методcontains()
, работа которого основана на методеequals()
, то методcontains
не сможет обнаружить ваш объект. При переопределении метода
equals()
не проверять наnull
переменные, что в конечном итоге заканчиваетсяNullPointerException
при вызовеequals()
. Ниже представлен корректный код.firstname == guest.firstname || (firstname != null && firstname.equals(guest.firstname));
- Третья распространенная ошибка это не переопределять метод
hashCode()
, а толькоequals()
. Вы обязаны переопределять оба методаequals()
иhashCode()
в Java. МетодhashCode
используется вhash
-коллекциях(напримерHashSet
), и чем меньше будет коллизий (одинаковый код при разных объектах) тем эффективнее эти коллекции будут работать с объектами вашего класса. - Последняя распространенная ошибка программистов в том, что при переопределении метода
equals()
не сохраняется соответствие между методамиequals()
иcompareTo()
, что является неформальным требованием для избежания хранения дубликатов вSet (SortedSet, TreeSet)
.
Подсказки как писать в Java метод equals
- Большинство IDE такие как NetBeans, Eclipse и IntelliJ IDEA обеспечивают поддержку генерации методов
equals()
иhashCode()
. В Eclipse нажмите правую кнопку -> source ->generate equals()
иhashCode()
. - Если в классе есть уникальный бизнес-ключ, то будет достаточно сделать проверку только на равенство этих полей. Как в нашем примере “id” - уникальный номер для каждого Person.
- При переопределении
hashCode()
в Java удостоверьтесь в использовании всех полей, что были использованы в методеequals()
. String
и классы-оболочки такие какInteger
,Float
иDouble
переопределяют методequals()
, ноStringBuffer
не переопределяет.- При любой возможности делайте поля
immutable
используяfinal
переменные в Java. - При сравнении
String
объектов используйтеequals()
вместо оператора==
. - Два объекта которые логически равны, но загружены из разных
ClassLoader
не могут быть равными. Помните, что проверка с помощьюgetClass()
вернетfalse
если класс-загрузчик разный. - Используйте
@Override
аннотацию также для методаhashCode
, так как это предупреждает неуловимые ошибки, например возвращаемое значение методаint
, однако некоторые программисты возвращаютlong
.
javarush.ru