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.
Как мы видим, при помощи операции == сравниваются ссылки на объекты. Но мы можем переопределять метод equals, тем самым задавая логику сравнения двух объектов. Например, рассмотрим сравнение двух одинаковых чисел, созданных при помощи класса Integer:
Понятно, что тут уже нет сравнения ссылок, а сравниваются 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
к этому типу. Потом сравнивайте каждый атрибут типа начиная с численных атрибутов (если имеются) потому что численные атрибуты проверяются быстрей. Сравнивайте атрибуты с помощью операторов И и ИЛИ (так называемые
) для объединения проверок с другими атрибутами.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