与equals方法相关的Java代码
我正在练习考试,发现一个我不明白的样本问题。
对于下面的代码,find输出是什么:
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);
– 因为这是唯一的情况,其中实例的静态typesequals
执行,参数的types是Test
类。
t3.equals(t3);
是第四个equals
语句(在静态count
variables的4个增量之后),因此打印4。
所有其他equals
语句执行Object
的equals
,因此不会打印任何内容。
更详细的解释:
由于t1
的静态(编译时)types是Object
,并且Test
类不覆盖该方法,因此t1.equals()
调用Object
的equals
而不pipe参数的types如何。 Object
类没有一个包含单个Test
参数的equals
方法,所以不pipet1
的dynamic(运行时types)如何,都不能调用equals(Test testje)
。
t3.equals()
可以执行Object
的equals
或Test
的equals,因为t3
的编译时间types是Test
,而Test
类有两个equals
方法(一个inheritance自Object
类,另一个在Test
定义类)。
被select的方法取决于参数的编译时间types:1.当参数是Object
(如t3.equals(o1);
或t3.equals(t2);
)时, Object
的equals
被调用,打印。 2.当参数是Test
,如t3.equals(t3);
,两个版本的equals
匹配该参数,但是由于方法重载的规则,select了最具体参数 – equals(Test testje)
的方法,并且打印count
variables。
Test中的equals方法获取Test的一个实例。
所有以前的尝试都是使用Object的一个实例进行的,它从Object类中采用了inheritance的方法:
public boolean equals(Object o){ return this == o; }
由于没有打印在那里,它不会打印任何值。
你的++count;
会增加计数值,所以当你实际打电话给你的时候
public boolean equals(Test testje){...
方法,即打印该值,count的值是4。
t3.equals(t3)
是唯一具有与方法签名public boolean equals (Test testje)
匹配的正确参数的行,因此它是程序中唯一实际调用该print语句的行。 这个问题旨在教你几件事情。
- 所有类都隐式扩展Object
- Object.java包含一个types为Object的equals方法
- 具有相同名称的多个方法可以存在,只要它们具有不同的参数 – 这被称为方法重载
- 在签名匹配运行时参数的方法方法重载是被调用的方法。
基本上这里的技巧是Test像所有java类一样隐式扩展Object。 Object包含一个采用Objecttypes的equals方法。 t1和t2是键入的,使得在运行时参数从不匹配在Test中定义的equals方法签名。 相反,它总是调用Object.java中的equals方法,因为基types是Object,在这种情况下,您可以访问的唯一方法是在Object.java中定义的方法,或者派生types是Object,在这种情况下
public boolean equals(Test testje)
不能进入,因为在这种情况下,在运行时参数是Objecttypes,它是Test的超类,而不是子类。 所以相反,它看着Test.java的隐式types的超类Object.java中的equals方法,它也包含一个equals方法,它只是碰巧有一个方法签名
public boolean equals (Object o)
在这种情况下在运行时匹配我们的参数,所以这个equals方法就是执行的方法。
注意在t3.equals(t3)
的情况下, t3.equals(t3)
的基types和派生types都是Test。
Test t3 = new Test ();
这意味着在运行时您正在调用Test.java中的equals方法,并且您传入的参数实际上是Testtypes,因此方法签名匹配并且Test.java中的代码将执行。 在这点数count == 4
。
为你加分知识:
@Override
您可能在几个地方看到的注释明确地指示编译器失败,如果它找不到在超类中的某个地方完全相同的签名的方法。 这对于知道你是否肯定要覆盖一个方法很有用,并且你想要确定你确实重写了这个方法,并且你没有意外地改变了超类或者子类中的方法,但是并不是这两个方法,并且引入了一个运行时错误该方法的错误实现被称为导致不需要的行为。
有两件关键的事情你应该知道。
-
重写的方法必须具有与其超类一样的确切签名。 (在你的例子中这个条件不符合。)
-
在一个对象的Java中,我们有两种types: 编译types和运行时types 。 在下面的例子中,
myobj
编译types是Object
但是其运行时types是Car
。public class Car{ @Override public boolean equals(Object o){ System.out.println("something"); return false; } }
Object myobj = new Car();
你也应该注意到,
myobj.equals(...)
导致在控制台中打印something
。