Java 与equals方法相关的代码
Java code related to equals method
我正在备考,发现了一道我看不懂的例题。
对于以下代码,找出输出是什么:
public class Test {
private static int count = 0;
public boolean equals(Test testje) {
System.out.println("count = " + count);
return false;
}
public static void main(String [] args) {
Object t1 = new Test();
Object t2 = new Test();
Test t3 = new Test();
Object o1 = new Object();
++count; t1.equals(t2);
++count; t1.equals(t3);
++count; t3.equals(o1);
++count; t3.equals(t3);
++count; t3.equals(t2);
}
}
这段代码的输出是count = 4
,但我不明白为什么。谁能帮帮我?
你应该注意的第一件事是 public boolean equals(Test testje)
不会 覆盖 Object
的 equals
,因为参数是 Test
而不是 Object
,所以签名不匹配。
因此 main
方法只调用一次 equals(Test testje)
- 当执行 t3.equals(t3);
时 - 因为这是实例 equals
的静态类型的唯一情况执行的对象和参数的类型是 Test
class。
t3.equals(t3);
是第 4 个 equals
语句(在静态 count
变量递增 4 次之后出现),因此打印 4。
所有其他 equals
语句执行 Object
的 equals
,因此不打印任何内容。
更详细的解释:
t1.equals()
调用 Object
的 equals
而不管参数的类型,因为 t1
的静态(编译时)类型是 Object
,并且 Test
class 不会覆盖该方法。 Object
class 没有带有单个 Test
参数的 equals
方法,因此无论动态(运行时)如何,都无法调用 equals(Test testje)
t1
.
类型)
t3.equals()
可以执行 Object
的 equals
或 Test
的等式,因为 t3
的编译时类型是 Test
,而 Test
class 有两个 equals
方法(一个继承自 Object
class,另一个定义在 Test
class).
选择的方法取决于参数的编译时类型:
1. 当参数为Object
(如t3.equals(o1);
或t3.equals(t2);
)时,调用Object
的equals
,但不打印任何内容。
2.当参数为Test
时,如t3.equals(t3);
,equals
的两个版本都匹配该参数,但由于方法重载的规则,具有最具体参数的方法-equals(Test testje)
- 被选中并打印 count
变量。
Test 中的 equals 方法采用 Test 的实例。
之前的所有尝试都是用Object的实例进行的,它采用了Object的继承方法class:
public boolean equals(Object o){
return this == o;
}
因为里面没有打印,所以不会打印任何值。
你的 ++count;
会增加 count 的值,所以当你真正调用你的
public boolean equals(Test testje){...
方法,确实打印那个值,count 的值为 4。
t3.equals(t3)
是唯一具有与方法签名匹配的正确参数的行 public boolean equals (Test testje)
因此它是程序中实际调用该打印语句的唯一行。这个问题是为了教你一些东西。
- 所有 class 隐式扩展对象
- Object.java 包含一个采用 Object
类型的 equals 方法
- 可以存在多个具有相同名称的方法,前提是它们具有不同的参数 - 这称为方法重载
- 方法方法重载谁的签名在运行时与参数匹配是被调用的方法。
本质上,这里的技巧是 Test 像所有 java classes 一样隐式扩展 Object。 Object 包含一个采用 Object 类型的 equals 方法。 t1 和 t2 的类型使得在 运行 时间参数永远不会匹配 Test 中定义的 equals 的方法签名。相反,它总是调用 Object.java 中的 equals 方法,因为基类型是 Object 在这种情况下,您可以访问的唯一方法是 Object.java 中定义的方法,或者派生类型是 Object 在这种情况下
public boolean equals(Test testje)
无法输入,因为在 运行 时参数是 Object 类型,它是 Test 的 Superclass,而不是 subclass。所以它会查看 Test.java 的隐式类型 superclass Object.java 中的 equals 方法,它也包含一个 equals 方法,它恰好有一个方法签名
public boolean equals (Object o)
在本例中,它与我们在 运行 时的参数匹配,因此执行的是这个 equals 方法。
注意t3.equals(t3)
t3 的基类型和派生类型都是Test。
Test t3 = new Test ();
这意味着在 运行 时,您正在调用 Test.java 中的 equals 方法,并且您传入的参数实际上是 Test 类型,因此方法签名匹配并且内部代码 Test.java 执行。此时count == 4
.
给你的额外知识点:
@Override
您可能在一些地方看到的注解明确指示编译器如果在 Superclass 中的某处找不到具有完全相同签名的方法则失败。这对于了解您是否确实 打算 重写一个方法很有用,并且您想要绝对确定您确实正在重写该方法并且您没有不小心更改 super 中的方法class 或 subclass 但不是两者都引入了 运行 时间错误,其中错误的方法实现被调用导致不需要的行为。
有两件重要的事情你应该知道。
覆盖的方法必须具有与其超类具有的完全相同的签名。 (在你的例子中这个条件不满足。)
在Java中对于一个对象,我们有两种类型:compile type and runtime type。在下面的示例中,myobj
的编译类型是 Object
但其运行时类型是 Car
.
public class Car{
@Override
public boolean equals(Object o){
System.out.println("something");
return false;
}
}
Object myobj = new Car();
您还应注意 myobj.equals(...)
导致在控制台中打印 something
。
我正在备考,发现了一道我看不懂的例题。
对于以下代码,找出输出是什么:
public class Test {
private static int count = 0;
public boolean equals(Test testje) {
System.out.println("count = " + count);
return false;
}
public static void main(String [] args) {
Object t1 = new Test();
Object t2 = new Test();
Test t3 = new Test();
Object o1 = new Object();
++count; t1.equals(t2);
++count; t1.equals(t3);
++count; t3.equals(o1);
++count; t3.equals(t3);
++count; t3.equals(t2);
}
}
这段代码的输出是count = 4
,但我不明白为什么。谁能帮帮我?
你应该注意的第一件事是 public boolean equals(Test testje)
不会 覆盖 Object
的 equals
,因为参数是 Test
而不是 Object
,所以签名不匹配。
因此 main
方法只调用一次 equals(Test testje)
- 当执行 t3.equals(t3);
时 - 因为这是实例 equals
的静态类型的唯一情况执行的对象和参数的类型是 Test
class。
t3.equals(t3);
是第 4 个 equals
语句(在静态 count
变量递增 4 次之后出现),因此打印 4。
所有其他 equals
语句执行 Object
的 equals
,因此不打印任何内容。
更详细的解释:
t1.equals()
调用 Object
的 equals
而不管参数的类型,因为 t1
的静态(编译时)类型是 Object
,并且 Test
class 不会覆盖该方法。 Object
class 没有带有单个 Test
参数的 equals
方法,因此无论动态(运行时)如何,都无法调用 equals(Test testje)
t1
.
t3.equals()
可以执行 Object
的 equals
或 Test
的等式,因为 t3
的编译时类型是 Test
,而 Test
class 有两个 equals
方法(一个继承自 Object
class,另一个定义在 Test
class).
选择的方法取决于参数的编译时类型:
1. 当参数为Object
(如t3.equals(o1);
或t3.equals(t2);
)时,调用Object
的equals
,但不打印任何内容。
2.当参数为Test
时,如t3.equals(t3);
,equals
的两个版本都匹配该参数,但由于方法重载的规则,具有最具体参数的方法-equals(Test testje)
- 被选中并打印 count
变量。
Test 中的 equals 方法采用 Test 的实例。
之前的所有尝试都是用Object的实例进行的,它采用了Object的继承方法class:
public boolean equals(Object o){
return this == o;
}
因为里面没有打印,所以不会打印任何值。
你的 ++count;
会增加 count 的值,所以当你真正调用你的
public boolean equals(Test testje){...
方法,确实打印那个值,count 的值为 4。
t3.equals(t3)
是唯一具有与方法签名匹配的正确参数的行 public boolean equals (Test testje)
因此它是程序中实际调用该打印语句的唯一行。这个问题是为了教你一些东西。
- 所有 class 隐式扩展对象
- Object.java 包含一个采用 Object 类型的 equals 方法
- 可以存在多个具有相同名称的方法,前提是它们具有不同的参数 - 这称为方法重载
- 方法方法重载谁的签名在运行时与参数匹配是被调用的方法。
本质上,这里的技巧是 Test 像所有 java classes 一样隐式扩展 Object。 Object 包含一个采用 Object 类型的 equals 方法。 t1 和 t2 的类型使得在 运行 时间参数永远不会匹配 Test 中定义的 equals 的方法签名。相反,它总是调用 Object.java 中的 equals 方法,因为基类型是 Object 在这种情况下,您可以访问的唯一方法是 Object.java 中定义的方法,或者派生类型是 Object 在这种情况下
public boolean equals(Test testje)
无法输入,因为在 运行 时参数是 Object 类型,它是 Test 的 Superclass,而不是 subclass。所以它会查看 Test.java 的隐式类型 superclass Object.java 中的 equals 方法,它也包含一个 equals 方法,它恰好有一个方法签名
public boolean equals (Object o)
在本例中,它与我们在 运行 时的参数匹配,因此执行的是这个 equals 方法。
注意t3.equals(t3)
t3 的基类型和派生类型都是Test。
Test t3 = new Test ();
这意味着在 运行 时,您正在调用 Test.java 中的 equals 方法,并且您传入的参数实际上是 Test 类型,因此方法签名匹配并且内部代码 Test.java 执行。此时count == 4
.
给你的额外知识点:
@Override
您可能在一些地方看到的注解明确指示编译器如果在 Superclass 中的某处找不到具有完全相同签名的方法则失败。这对于了解您是否确实 打算 重写一个方法很有用,并且您想要绝对确定您确实正在重写该方法并且您没有不小心更改 super 中的方法class 或 subclass 但不是两者都引入了 运行 时间错误,其中错误的方法实现被调用导致不需要的行为。
有两件重要的事情你应该知道。
覆盖的方法必须具有与其超类具有的完全相同的签名。 (在你的例子中这个条件不满足。)
在Java中对于一个对象,我们有两种类型:compile type and runtime type。在下面的示例中,
myobj
的编译类型是Object
但其运行时类型是Car
.public class Car{ @Override public boolean equals(Object o){ System.out.println("something"); return false; } }
Object myobj = new Car();
您还应注意
myobj.equals(...)
导致在控制台中打印something
。