与equals方法相关的Java代码

Dri*_*ens 74 java equals

我正在练习考试,发现了一个我不明白的样本问题.

对于以下代码,找到输出的内容:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这段代码的输出是count = 4,但我不明白为什么.谁能帮我?

Era*_*ran 112

你要注意的第一件事是public boolean equals(Test testje) 不要覆盖Object's equals,因为参数Test不是Object,所以签名不匹配.

因此,该main方法只equals(Test testje)执行一次 - 执行时t3.equals(t3);- 因为这equals是执行实例的静态类型并且参数类型是Test类的唯一情况.

t3.equals(t3);是第4个equals语句(在静态count变量的4个增量之后出现),因此打印4.

所有其他equals语句执行Objectequals,因此打印什么.

更详细的解释:

t1.equals()呼叫Objectequals不管参数的类型的,因为静态(编译时间)类型t1IS Object,和Test类不覆盖该方法.所述Object类不具有equals与单个方法Test参数,所以equals(Test testje)不能称为,无论动态(运行时类型)的t1.

t3.equals()可以执行任何ObjectequalsTest's等于,因为在编译时间类型t3Test,并且Test类有两个equals方法(一个来自继承Object类,并在定义的其它Test类).

选择的方法取决于参数的编译时类型:1.当参数为Object(如在t3.equals(o1);or中t3.equals(t2);)时,调用Objects equals并且不打印任何内容.2.当参数是Test,如在t3.equals(t3);,这两个版本equals匹配的参数,但由于方法重载的规则,具有最具体参数的方法- equals(Test testje)-被选择和count被打印变量.

  • Geeeez,这就是我使用@Override注释的原因 (19认同)

Stu*_*ske 11

Test中的equals方法接受Test的一个实例.

以前的所有尝试都是使用Object的实例进行的,它从Object类中获取了继承的方法:

public boolean equals(Object o){
  return this == o;
}
Run Code Online (Sandbox Code Playgroud)

由于那里没有打印,因此不会打印任何值.

++count;会增加计数值,所以你实际打电话给你的那一刻

public boolean equals(Test testje){...
Run Code Online (Sandbox Code Playgroud)

方法,打印该值,count的值为4.


Jam*_*ler 7

t3.equals(t3)是唯一具有与方法签名匹配的正确参数的行,public boolean equals (Test testje)因此它是程序中实际调用该print语句的唯一行.这个问题旨在教你一些事情.

  • 所有类都隐式扩展Object
  • Object.java包含一个采用Object类型的equals方法
  • 如果它们具有不同的参数,则可以存在多个具有相同名称的方法 - 这称为方法重载
  • 方法方法重载谁的签名与运行时的参数匹配是被调用的方法.

基本上这里的技巧是Test像所有java类一样隐式扩展Object.Object包含一个采用Object类型的equals方法.输入t1和t2,使得在运行时参数永远不会匹配Test中定义的equals方法签名.相反,它始终调用Object.java中的equals方法,因为基类型是Object,在这种情况下,您可以访问的唯一方法是Object.java中定义的方法,或者派生类型是Object,在这种情况下

public boolean equals(Test testje)
Run Code Online (Sandbox Code Playgroud)

无法输入,因为在这种情况下,在运行时参数是Object类型,它是Test的超类,而不是子类.因此,而不是它看起来在Test.java的隐式类型的超Object.java equals方法,其还包含一个equals方法,这恰好有一个方法签名

public boolean equals (Object o)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,在运行时匹配我们的参数,所以这个equals方法是执行的方法.

注意,在t3.equals(t3)基本类型和t3的派生类型都是Test的情况下.

Test t3 = new Test ();
Run Code Online (Sandbox Code Playgroud)

这意味着在运行时,您在Test.java中调用equals方法,并且您传入的参数实际上是Test类型,因此方法签名匹配并且Test.java中的代码执行.在这一点上count == 4.

为您带来一点知识:

@Override 
Run Code Online (Sandbox Code Playgroud)

您可能在一些地方看到的注释显式指示编译器失败,如果它没有在超类中找到具有完全相同签名的方法.这有助于知道你是否肯定打算覆盖一个方法,并且你想要绝对确定你真的覆盖了该方法并且你没有意外地改变了超类或子类中的方法而不是两者并且引入了运行时错误调用该方法的错误实现导致不必要的行为.