我有一个扩展Person类的学生类。我的超级类中没有equals方法,只有我的子类中的两个,如图所示。我正在尝试理解我的第二、第三和第四个print语句的运行时行为。语句1调用了接受学生参数的equals方法,这是有意义的,因为要比较的两个对象都是声明类型的学生。但是,语句2调用了接受人参数的equals方法,而最后两个语句调用了Object类中的equals方法。有人能解释一下为什么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
根据声明的类型,在编译时确定使用哪个重载方法。
在第二种情况下,您已经声明s3是个人,因此使用了equals(Person)
方法。
在第3和第4种情况下,您已将变量声明为Person。Person没有equals()方法,因此编译器假设您希望使用来自对象的默认方法:
boolean equals(Object o);
您尚未在任何类中重写该方法,因此默认方法是在运行时使用的方法。
其中Person对象是调用学生重载的equals的参数。这就是为什么您会得到print语句。如果您希望将其作为学生进行比较,那么您需要对其进行类型转换。
在对Person对象调用equals的情况下,它最终返回一个假as。equals未在Person类中实现。。。然后它默认为对象的实现,即“检查Null,然后检查引用是否相同……否则返回false”。您可以在JDK的源代码中查看实现。
您所犯的最大错误是,使用equals
方法缺少@Override
注释。一旦你做了,例如。
@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
或学生
类型作为参数的定义。
在这四个调用中,都不会调用被重写的对象equals。
毫无疑问,第一次调用中将调用Student#equals
,因为两个引用均为Student
类型。在剩下的三个调用中,由于最接近的匹配,将调用Person#equals。
您可以查看此演示以获取插图。
如果如图所示,将两个方法放在学生内部,您应该更容易理解输出。
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
如果您希望在最后两种情况下也调用学生#equals
,则需要将s3
转换为学生
,如下所示:
System.out.println(((Student) s3).equals(s4)); // 3.1
System.out.println(((Student) s3).equals(s1)); // 4.1
通常,具有固定参数数的方法优于具有可变参数数的重载方法。但是,该示例的行为不同: 输出: main的第三行用一个参数调用该方法,该参数是一个包含两个元素的字符串[]。但这并不是用一个参数执行方法,而是执行varargs方法,就像我给了它两个参数一样(这有点正常,因为它是一个数组)。 现在的问题是:这应该发生吗?我是否发现了错误或未记录的行为?它这样做的原因是什么? 我为什么这么做:我想做一个快捷方
我有以下代码片段: 如果我调用foo(null)为什么没有歧义?为什么程序调用foo(字符串x)而不是foo(对象x)?
问题内容: 考虑以下Java代码: 第一个打印语句打印,第二个打印语句。 如果这是故意的行为,这将如何帮助Java编程? 如果这不是故意行为,那么这是否是Java中的缺陷? 问题答案: 我将保留您的问题,但您应该知道,如果该问题的目的是让您学习并且您的解决方案是询问StackOverflow,那么您会很受伤。那边… 此行为是故意的。 默认方法on 比较 内存地址 ,这意味着所有对象都互不相同(仅对
本文向大家介绍java中重写equals()方法的同时要重写hashcode()方法(详解),包括了java中重写equals()方法的同时要重写hashcode()方法(详解)的使用技巧和注意事项,需要的朋友参考一下 object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 tr
本文向大家介绍java中为何重写equals时必须重写hashCode方法详解,包括了java中为何重写equals时必须重写hashCode方法详解的使用技巧和注意事项,需要的朋友参考一下 前言 大家都知道,equals和hashcode是java.lang.Object类的两个重要的方法,在实际应用中常常需要重写这两个方法,但至于为什么重写这两个方法很多人都搞不明白。 在上一篇博文Java中e
本文向大家介绍为什么在重写 equals方法的同时必须重写 hashcode方法,包括了为什么在重写 equals方法的同时必须重写 hashcode方法的使用技巧和注意事项,需要的朋友参考一下 我们都知道Java语言是完全面向对象的,在java中,所有的对象都是继承于Object类。 其 equals 方法比较的是两个对象的引用指向的地址,hashcode 是一个本地方法,返回的是对象地址值。O