У меня есть класс 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
Я не уверен, как? :\
@Стив, теперь я знаю
@Progman, частично! Я все еще пытаюсь понять, почему в операторах 3 и 4 вызывается equals в классе объектов вместо одного из двух в классе ученика.
Где объект 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 - я добавил ссылку на демо. Не стесняйтесь комментировать в случае каких-либо сомнений / проблем.
Это имеет смысл, однако это был не мой вопрос. У меня есть как equals(Student s), так и equals(Person p) внутри подкласса и ни одного в моем суперклассе. Можете ли вы помочь объяснить операторы печати 3 и 4? у меня первые два
@ amuu00 - я добавил раздел обновления, чтобы объяснить вывод для этого требования. Не стесняйтесь комментировать в случае каких-либо сомнений / проблем.
Сделанный! Спасибо, Арвинд, мое замешательство возникло из-за следующего: s3.equals(s4) //s3 имеет тип Person во время объявления, и код компилируется, потому что он наследует метод equals от объектного класса, и компилятор доволен. Однако во время выполнения, поскольку Java является динамически типизированной и у нас есть Person s3 = new Student(), он будет запускать equals внутри класса Student. Понимаете? И я подумал, что он должен запускать один из двух методов equals в классе Student.
Я все еще немного смущен, почему это не так.
@ amuu00 - я добавил еще два утверждения (как 3.1 и 4.1) в разделе «Обновление». Я также рекомендую вам проверить это обсуждение. Не стесняйтесь комментировать в случае каких-либо сомнений / проблем.
Давайте продолжим обсуждение в чате.
Пожалуйста, отправляйте текст, а не изображения текста. Очень сложно тестировать ваш код и вносить в него изменения, когда это изображение.