Поведение во время выполнения при перегрузке метода Equals в Java

У меня есть класс Student, который расширяет класс Person. У меня нет метода equals внутри моего суперкласса, только два в моем подклассе, как показано на рисунке. Я пытаюсь понять поведение во время выполнения моих 2-го, 3-го и 4-го операторов печати. Оператор 1 вызывает метод equals, который принимает параметр student, что имеет смысл, поскольку оба сравниваемых объекта объявлены как тип Student. Однако оператор 2 вызывает метод equals, который принимает параметр person, в то время как последние 2 оператора вызывают метод equals в классе Object. Может кто-нибудь объяснить, почему это так, когда Java динамически типизирована, а фактический объект времени выполнения всегда является студентом. Заранее извиняюсь за возможные ошибки! Я новичок здесь и новичок в Java. Я не слишком озабочен выводом каждого метода, а только тем, какой из них вызывается и почему.

public boolean equals(Student s) {
    System.out.println("inside student equals");
    return true;
}

public boolean equals(Person p) {
    System.out.println("inside person equals");
    return false;
}

public static void main(String[] args) {
    Student s1 = new Student("John", "1", 10, 1.0, 10);
    Student s2 = new Student("John", "1", 10, 1.0, 10);

    Person s3 = new Student("John", "1", 10, 1.0, 10);
    Person s4 = new Student("John", "1", 10, 1.0, 10);

    System.out.println(s1.equals(s2)); // 1
    System.out.println(s1.equals(s3)); // 2

    System.out.println(s3.equals(s4)); // 3
    System.out.println(s3.equals(s1)); // 4
}

Выход:

    inside student equals
    true
    inside person equals
    false
    false
    false

Пожалуйста, отправляйте текст, а не изображения текста. Очень сложно тестировать ваш код и вносить в него изменения, когда это изображение.

Aplet123 20.12.2020 19:12

Я не уверен, как? :\

amuu00 20.12.2020 19:13
meta.stackexchange.com/q/22186/398082
Aplet123 20.12.2020 19:14

@Стив, теперь я знаю

amuu00 20.12.2020 19:20

@Progman, частично! Я все еще пытаюсь понять, почему в операторах 3 и 4 вызывается equals в классе объектов вместо одного из двух в классе ученика.

amuu00 20.12.2020 19:48
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
Что такое управление транзакциями JDBC и как оно используется для поддержания согласованности данных?
Что такое управление транзакциями JDBC и как оно используется для поддержания согласованности данных?
Управление транзакциями JDBC - это мощная функция, которая позволяет рассматривать группу операций с базой данных как единую единицу работы. Оно...
Выполнение HTTP-запроса с помощью Spring WebClient: GET
Выполнение HTTP-запроса с помощью Spring WebClient: GET
WebClient - это реактивный веб-клиент, представленный в Spring 5. Это реактивное, неблокирующее решение, работающее по протоколу HTTP/1.1.
Gradle за прокси-сервером
Gradle за прокси-сервером
Создайте проект Gradle под сетевым прокси.
1
5
104
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Где объект Person является параметром, вызывается перегруженный эквивалент Student. Вот почему вы получаете оператор печати. Если вы хотите, чтобы его сравнивали со студентом, вам нужно привести его к типу.

В случаях, когда equals вызывается для объекта Person, он возвращает false, поскольку .equals не реализован в классе Person... тогда по умолчанию используется реализация Object, которая "проверить значение Null, а затем проверить, является ли ссылка той же самой.. .иначе вернуть ложь". Вы можете проверить реализацию в источнике JDK.

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

Во втором случае вы объявили s3 как Person, поэтому используется метод equals(Person).

В 3-м и 4-м случаях вы объявили переменную как Person. У Person нет метода equals(), поэтому компилятор предполагает, что вы хотите использовать метод по умолчанию из Object:

boolean equals(Object o);

Вы не переопределили этот метод ни в одном из классов, поэтому этот метод по умолчанию используется во время выполнения.

Ответ принят как подходящий

Самая большая ошибка, которую вы сделали, это отсутствие аннотации @Override в методе equals. Как только вы сделаете это, например.

@Override
public boolean equals(Object obj) {
    System.out.println("inside person equals");
    return false;
}

И

@Override
public boolean equals(Object obj) {
    System.out.println("inside student equals");
    return true;
}

Как только вы это сделаете, ваша IDE завершит компиляцию, заставив вас исправить определения, которые должны быть типами Object вместо Person или Student в качестве параметров.

О выходе, который вы получаете:

Ни в одном из четырех вызовов не будет вызываться переопределенный Object#equals.

Нет сомнений, что Student#equals будет вызываться при первом вызове, так как обе ссылки относятся к типу Student. В оставшихся трех вызовах Person#equals будет вызываться из-за ближайшего совпадения.

Вы можете посмотреть это демо для иллюстрации.

Обновлять

Если вы поместите оба метода equals внутрь Student, как показано здесь, вам будет еще проще понять вывод.

s1.equals(s2) // 1 -> "inside student equals" will be printed because the param, s2 is of type, Student
s1.equals(s3) // 2 -> "inside person equals" will be printed because the param, s3 is of type, Person

s3.equals(s4) // 3 -> s3 is of type, Person but Person has not overridden equals, therefore Object#equals will be called
s3.equals(s1) // 4 -> s3 is of type, Person but Person has not overridden equals, therefore Object#equals will be called

Если вы хотите, чтобы Student#equals вызывалась и в последних двух случаях, вам нужно привести s3 к Student, как показано ниже:

System.out.println(((Student) s3).equals(s4)); // 3.1
System.out.println(((Student) s3).equals(s1)); // 4.1

Привет Арвинд, спасибо за ваш ответ. Что мне трудно понять, так это то, что если Object equals никогда не вызывается, а только Person equals, как вы сказали, то почему он не печатает «внутреннее равенство человека» в последних двух утверждениях?

amuu00 20.12.2020 20:13

@ amuu00 - я добавил ссылку на демо. Не стесняйтесь комментировать в случае каких-либо сомнений / проблем.

Arvind Kumar Avinash 20.12.2020 20:23

Это имеет смысл, однако это был не мой вопрос. У меня есть как equals(Student s), так и equals(Person p) внутри подкласса и ни одного в моем суперклассе. Можете ли вы помочь объяснить операторы печати 3 и 4? у меня первые два

amuu00 20.12.2020 20:34

@ amuu00 - я добавил раздел обновления, чтобы объяснить вывод для этого требования. Не стесняйтесь комментировать в случае каких-либо сомнений / проблем.

Arvind Kumar Avinash 20.12.2020 20:45

Сделанный! Спасибо, Арвинд, мое замешательство возникло из-за следующего: s3.equals(s4) //s3 имеет тип Person во время объявления, и код компилируется, потому что он наследует метод equals от объектного класса, и компилятор доволен. Однако во время выполнения, поскольку Java является динамически типизированной и у нас есть Person s3 = new Student(), он будет запускать equals внутри класса Student. Понимаете? И я подумал, что он должен запускать один из двух методов equals в классе Student.

amuu00 20.12.2020 21:03

Я все еще немного смущен, почему это не так.

amuu00 20.12.2020 21:04

@ amuu00 - я добавил еще два утверждения (как 3.1 и 4.1) в разделе «Обновление». Я также рекомендую вам проверить это обсуждение. Не стесняйтесь комментировать в случае каких-либо сомнений / проблем.

Arvind Kumar Avinash 20.12.2020 21:17

Давайте продолжим обсуждение в чате.

amuu00 20.12.2020 21:24

Другие вопросы по теме