Сначала у меня код выглядел так :
public boolean equals(Iphone iphone){
if(this == iphone)
return true;
if(iphone == null || getClass() != iphone.getClass()){
return false;
}
return this.model == iphone.model && this.color == iphone.color && this.price == iphone.price;
}
После уже переписал через Object object и валидатор принял задачу.
Соответственно вопрос, зачем в equals указывать класс Object и потом делать приведение типов объекта от Object к нашему текущему, а именно к Iphone,
если можно сразу написать под нужный нам объект?
Данный метод equals все-равно не будет универсальным если мы захотим сравнивать какие то другие объекты, тк поля там будут явно другие.
Так же вопрос, если мы задаем equals через alt+ insert автоматически, то в финальном ретурне у нас идет строка:
return price == iphone.price && Objects.equals(model,iphone.model) && Objects.equals(color, iphone.color);
почему для прайс так же не происывают equals через Objects как для других полей?
Михаил
16 уровень
Можно ли так решать и в чем отличие?
Решен
Комментарии (13)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Максим Аракелян
4 сентября 2022, 10:15
Сколько я времени зря убил!!! При написании метода equals компилятор по умолчанию предложил Objects вместо Object и понеслась: изучение ключевого слова this, вырванные волосы и вот в конце СВЕТ.
Спасибо всем участникам диалога. всё понятно разжёвано и мои, в том числе, вопросы сняты.
0
hidden #598481
29 августа 2022, 15:32
Соответственно вопрос, зачем в equals указывать класс Object
Начнём с того, что не Object, а Objects, это разные классы. Objects - это утилитный класс со всякими статическими методами, удобными для использования, в частности с equals, сравнивающим между собой два объекта. Использовать его необязательно, а тупо удобнее. Но давай реализуем без него, чтобы ответить на главный твой вопрос, что не так с кодом:
Если ты вспомнишь первые лекции, то там говорилось, что через "==" можно сравнивать только примитивы, а объекты надо сравнивать методом equals, типа this.color.equals(iphone.color). Это нужно делать потому, что ссылочные объекты могут обладать одинаковыми характеристиками, но при этом это всё равно будут два разных объекта, на каждый из которых будет вести своя собственная ссылка. А в переменных же лежат именно ссылки на объекты, и при сравнении через "==" ты сравнишь ссылки, увидишь что ссылки разные и решишь, что объекты тоже разные, хотя они на самым деле одинаковые. Именно за этим мы и определяем метод equals в классе Iphone, в противном случае мы могли бы просто сравнить iphone1==iphone2 и дело с концом. Но мы не можем. И поэтому мы сами определяем, какие два айфона будем считать одинаковыми: в данном случае одного цвета, одной модели и цены одновременно.
И казалось бы, вот же ответ: this.color.equals(iphone.color) и аналогично с моделью сделать и всё.
Только проблема в том, что если значение у поля не задано, то это поле содержит null, а если у null вызвать какой-нибудь метод, то вылезет NullPointerException. Поэтому перед каждой проверкой нужно проверять, что если у одного объекта в поле лежит null, то и у другого тоже должен быть null, а если у одного не null, то и у другого содержимое должно быть точно таким же.
+3
hidden #598481
29 августа 2022, 15:33
И если так проверить все поля по очереди, то получишь одинаковые объекты.
А цена сравнивается через ==, потому что она типа int, примитив. Числа можно сравнивать между собой прямо так.
0
Михаил
29 августа 2022, 18:48
По поводу Object не совсем понял, у нас ведь idea выдает то, что мы передаем в метод equals объект класса Object, я не до конца понимаю почему пишем, что наш объект будет именно этого класса, а не нашего класса для которого мы делаем метод.
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return year == car.year && Objects.equals(model, car.model);
}
Почему бы просто не написать, public boolean equals(Car car) , по сути проверки на ссылки, на null объекты так же пройдут, сравнить поля так же можно через Objects.equals, разницы все никак не могу найти.
+ я правильно понимаю, что стандартные equals которая формирует idea не совсем корректные, тк там нет никаких проверок на "null" ?
Просто опять же если опираться на решение, которое предлагают нам ребята из джавараша, то там так таковых проверок на null для каждого поля не предусмотрено, что странно.
Ведь эта проверка " o == null " все же относится к проверке объекта на null который мы будем сравнивать, а не его какого-то поля.
+1
hidden #598481
29 августа 2022, 20:10полезный
А, я твой вопрос про Object изначально не так понял.
Да, дело не в идее, а дело в том, что в классе Object есть метод equals(), аргументом у которого является другой объект типа Object. Этот метод позволяет нам сравнить два любых объекта и сказать, являются ли они одинаковыми между собой или нет.
Этот метод сначала проверяет, что объекты между собой одного класса, и если это действительно так, то имеет смысл сравнивать между собой поля этих объектов, а в противном случае, если это объекты равных классов, то и сравнивать между собой дальше их не имеет смысла, объекты точно разные.
И поскольку у нас любой класс является наследником класса Object, то этот метод можно вызвать у объекта вообще любого класса. То есть в любом классе, описано это или нет можно вызвать метод equals и передать параметром любой другой объект. Ты конечно можешь в своём классе Iphone описать метод equals, у которого параметром будет другой объект Iphone, но проблема в том, что этот метод не будет переопределять поведение оригинального метода equals: чтобы сработало переопределение, нужно чтобы у двух методов совпадала сигнатура, включающая в себя название методов, количество, порядок и типы параметров, а у тебя типы будут разными.
Метод equals много где используется, даже когда ты этого не замечаешь. Например, когда ты добавляешь объекты в набор (Set), в нём могут содержаться только уникальные элементы. Для проверки уникальности будет вызываться метод equals (ведь ты помнишь, его можно вызвать у любого объекта). Коллекция понятия не будет иметь о том, что в твоём классе описан другой метод equals с параметром типа Iphone, она про твой класс ничего не знает. Зато знает, что у объекта любого класса можно вызвать метод equals(Object obj), потому что это задано самой спецификацией джавы и описано в её библиотеке.
Мысль закончу ниже.
+4
hidden #598481
29 августа 2022, 20:25
И именно поэтому тебе нужно переопределить именно метод с параметром типа Object. Переопределяя метод, ты как бы говоришь: другие объекты вы можете сравнивать как хотите, а вот чтобы сравнить сказать, что айфон был тождественен другому объекту, нужно, чтобы выполнялись следующие условия:
- если айфон сравнивать с самим собой, то они одинаковые;
- другой объект не должен быть null;
- другой объект тоже должен быть айфоном;
- цена другого айфона должна быть такой же, как у моего;
- модели этих айфонов должны совпадать;
- цвет этих айфонов должен совпадать.
То есть ты сам определяешь, какие два айфона будут считаться одинаковыми и заменяешь стандартное поведение из метода equals своим.
Именно это и требуется реализовать в задаче. На первых двух пунктах останавливаться подробнее не буду, думаю они вопросов не вызывают. Если в первых двух ифах мы не вышли из метода, значит ни одно из условий выше не выполнилось. Это означает, что во-первых мы не сравниваем объект сам с собой, а во-вторых классы наших объектов совпадают, то есть в Object object хранится объект типа Iphone. Значит можно выполнить явное приведение типа:
Остаётся сравнить между собой три пары полей. Первое поле - это цена (price). Она является примитивом, типа int. Поэтому цены можно сравнить между собой через "==". Сравнили и посмотрели. Если цены разные, то остальное можно не сравнивать, айфоны точно разные. А если цены одинаковые, то узнаем, когда сравним между собой модели и цвет.
Продолжение ниже.
+4
hidden #598481
29 августа 2022, 20:45
Итого, мы знаем, что оба объекта - это айфоны, и у них одинаковые цены. Осталось сравнить между собой модели и цвета. Начнём с моделей. Каждая из моделей может быть null, мы от этого не застрахованы. А может быть не null. Поэтому возможны 4 варианта:
- обе null;
- первая null, вторая не null;
- первая не null, вторая null;
- обе не null.
Если this.model==null, а мы вдруг вызовем у неё метод equals, то возникнет исключение. Поэтому перед тем, как вызывать, надо проверить, что там не null:
Таким образом мы сравнили между собой две модели. Если обе проверки прошли мимо, значит модели совпадают, и осталось проверить цвета. С ними абсолютно аналогично, выполняются те же самые проверки.
Если и цвета совпали, то можно в конце написать return true; потому что если бы было не тру, то сработала бы какая-то их проверок, и false бы вернулось раньше.
А чтобы каждый раз руками не писать такую длинную колбасу, а если оно налл, а если вдруг не налл, то тогда сравниваем, и т.д., просто для удобства, все это запихнули внутрь утилитного метода equals класса Objects, он внутри уже содержит проверку на null и на равенство, поэтому весь последний блок кода тождественен написи:Если этот метод вернул true, значит либо обе модели null, либо обе не null, но тогда при этом одинаковые. Поэтому идея тебе предлагает просто лаконичную запись вместо того, чтобы объяснять тебе по шагам, как я :)
+1
KIRAРазработчик в prosv.ruExpert
29 августа 2022, 21:27полезный
Простой класс у которого создали метод как вы предложили с параметром Iphone, а не Object. У нас есть 3 телефона и метод который всегда возвращает true, подумайте какой должен быть вывод, а потом можете проверить себя запустив код.
+1
Михаил
30 августа 2022, 09:35
В целом все что я и хотел понять, а именно :
"Ты конечно можешь в своём классе Iphone описать метод equals, у которого параметром будет другой объект Iphone, но проблема в том, что этот метод не будет переопределять поведение оригинального метода equals: чтобы сработало переопределение, нужно чтобы у двух методов совпадала сигнатура, включающая в себя название методов, количество, порядок и типы параметров, а у тебя типы будут разными."
и второй момент, что в Objects.equals уже заложена проверка на null (время начинать учиться читать документацию оракл)
Огромное спасибо за разъяснение.
+1
Михаил
30 августа 2022, 09:45
Если я все правильно понимаю, то :
System.out.println(iphone1.equals(iphone2)); // здесь мы вызываем equals Object`a потому и вернется false
System.out.println(iphone2.equals(iphone1)); // вот тут конечно вопрос, почему не используется переопределенный метод equals, но возможно из-за того, что объекты различаются классом.
System.out.println(iphone2.equals(iphone3)); // здесь используется наш equals который вернет true.
0
KIRAРазработчик в prosv.ruExpert
30 августа 2022, 09:56полезный
System.out.println(iphone2.equals(iphone1));
Объекты одинаковые, тип ссылки разный. Из за того что мы передаем ссылку типа Object, а в классе Iphone нет метода который принимает Object, вызывается метод родителя и сравниваются ссылки возвращая false
+2
Михаил
30 августа 2022, 10:11
Спасибо
0
ИгорьКурган
29 августа 2022, 14:03
dwutm t
0