I am practicing for an exam, and found a sample problem that I don't understand.
我正在练习考试,发现了一个我不懂的样本问题。
For the following code, find what the output is:
对于以下代码,查找输出是什么:
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);
}
}
The output of this code is count = 4
, but I don't understand why. Can anyone help me?
这段代码的输出是count = 4,但是我不明白为什么。谁能帮我吗?
4 个解决方案
#1
112
The first thing you should note is that public boolean equals(Test testje)
doesn't override Object
's equals
, since the argument is Test
instead of Object
, so the signatures don't match.
首先要注意的是,公共布尔值(Test testje)不会覆盖对象的值,因为参数是Test而不是Object,所以签名不匹配。
Therefore the main
method calls equals(Test testje)
exactly once - when executing t3.equals(t3);
- since that's the only case in which both the static type of the instance equals
is executed for and the type of the argument are the Test
class.
因此,当执行t3.equals(t3)时,主方法调用等于(Test testje)一次;-因为这是唯一的一种情况,实例等于的静态类型和参数的类型都是测试类。
t3.equals(t3);
is the 4th equals
statement (which comes after 4 increments of the static count
variable), so 4 is printed.
t3.equals(t3);是第4个equals语句(在静态count变量的4个增量之后),因此输出4。
All the other equals
statements execute Object
's equals
, and therefore print nothing.
所有其他的等号语句执行对象的等号,因此不打印任何东西。
A more detailed explanation :
更详细的解释是:
t1.equals()
calls Object
's equals
regardless of the type of the argument, since the static (compile time) type of t1
is Object
, and the Test
class doesn't override that method. The Object
class doesn't have an equals
method with a single Test
argument, so equals(Test testje)
can't be called, regardless of the dynamic (runtime type) of t1
.
t1.equals()调用Object's equals,不管参数的类型如何,因为t1的静态(编译时)类型是Object,并且测试类不会覆盖该方法。对象类没有带有单个测试参数的equals方法,因此无论t1的动态(运行时类型)如何,都不能调用equals(Test testje)。
t3.equals()
can execute either Object
's equals
or Test
's equals, since the compile time type of t3
is Test
, and the Test
class has two equals
methods (one inherited from the Object
class and the other defined in the Test
class).
t3.equals()可以执行对象的equals或Test的equals,因为t3的编译时类型是Test,并且Test类有两个equals方法(一个继承自Object类,另一个定义在Test类中)。
The method being chosen depends on the compile time type of the argument : 1. When the argument is Object
(as in t3.equals(o1);
or t3.equals(t2);
), Object
's equals
is called and nothing is printed. 2. When the argument is Test
, as in t3.equals(t3);
, both versions of equals
match that argument, but due to the rules of method overloading, the method with the most specific argument - equals(Test testje)
- is chosen and the count
variable is printed.
所选择的方法取决于参数的编译时类型:1。当参数为Object(如t3.equals(o1));或t3.equals(t2);),对象的equals,并无打印。2。当参数被测试时,如t3.equals(t3)中;,两个版本的equals都匹配该参数,但是由于方法重载的规则,选择具有最特定参数的方法—equals(Test testje)—并打印count变量。
#2
11
The equals method in Test takes an instance of Test.
测试中的equals方法接受一个测试实例。
All the previous attempts have been made with an instance of Object, which take the inherrited method from the Object class:
之前所有的尝试都是通过对象实例进行的,对象实例采用对象类继承的方法:
public boolean equals(Object o){
return this == o;
}
Since there is no print in there, it won't print any value.
因为里面没有打印,所以不会打印任何值。
Your ++count;
will increment the value of count, so the moment when you actually call your
你的+ +计数;会增加计数的值,所以当你真正调用你的
public boolean equals(Test testje){...
method, that does print that value, the value of count is 4.
方法,它会打印那个值,count的值是4。
#3
7
t3.equals(t3)
is the only line which has the right arguments that match the method signature public boolean equals (Test testje)
so it's the only line in the program which actually calls that print statement. This question is designed to teach you a few things.
t3.equals(t3)是唯一的一行,它具有与方法签名公共布尔等于(Test testje)匹配的正确参数,因此它是程序中唯一调用打印语句的行。这个问题的目的是教你一些东西。
- All class implicitly extend Object
- 所有类都隐式地扩展对象
- Object.java contains an equals method which takes type Object
- 对象。java包含一个获取类型对象的equals方法
- multiple methods with the same name can exist provided they have different arguments - this is known as method overloading
- 只要有不同的参数,就可以存在具有相同名称的多个方法——这就是所谓的方法重载
- the method method overload who's signature matches the arguments at runtime is the method that gets invoked.
- 在运行时签名匹配参数的方法重载是被调用的方法。
Essentially the trick here is that Test implicitly extends Object like all java classes do. Object contains an equals method that takes type Object. t1 and t2 are typed such that at run time the arguments never match the method signature of equals that is defined in Test. Instead it's always calling into the equals method in Object.java because either the base type Is Object in which case the only methods you have access to are the ones defined in Object.java or the derived type is Object in which case
本质上,这里的诀窍是测试隐式地扩展对象,就像所有java类所做的那样。对象包含一个获取类型对象的equals方法。t1和t2的类型是这样的:在运行时,参数永远不会与测试中定义的方法签名相等。相反,它总是调用对象中的equals方法。因为要么基类型是对象,在这种情况下,您只能访问对象中定义的方法。在这种情况下,java或派生类型是Object
public boolean equals(Test testje)
Cannot be entered because in that case at runtime the argument is of type Object which is a Superclass of Test, not a subclass. So instead it looks at the equals method in the Test.java's implicitly typed superclass Object.java which also contains an equals method, which just happens to have a method signature of
不能输入,因为在运行时,参数是类型对象,它是测试的超类,而不是子类。相反,它会在测试中查看equals方法。java的隐式类型化的超类对象。java也包含一个equals方法,它刚好有一个方法签名
public boolean equals (Object o)
which in this case match our arguments at runtime so this equals method is the one that executes.
在这种情况下,它与我们在运行时的参数相匹配所以这个等于方法就是执行的那个。
Notice in the case of t3.equals(t3)
both the base type and the derived type of t3 are Test.
注意,在t3.equals(t3)的情况下,t3的基类型和派生类型都是Test。
Test t3 = new Test ();
this means that at runtime you are calling the equals method in Test.java and the argument you are passing in is actually of type Test so the method signatures match and the code inside Test.java executes. At this point count == 4
.
这意味着在运行时,您正在测试中调用equals方法。java和您传入的参数实际上是类型测试,所以方法签名匹配和测试中的代码。java执行。此时count == 4。
Bonus bit of knowledge for you:
给你一点额外的知识:
@Override
annotation you may have seen in a few places explicitly instructs the compiler to fail if it does not find method with the exact same signature somewhere in a Superclass. This is useful to know if you definitely intend to override a method and you want to be absolutely sure that you really are overriding the method and you haven't accidentally changed the method in either the superclass or subclass but not both and Introduced a runtime error where the wrong implementation of the method is being called causing unwanted behavior.
如果编译器在超类的某个地方找不到具有相同签名的方法,那么您可能在一些地方看到注释明确地指示编译器失败。这肯定有助于知道你打算覆盖一个方法,你要绝对相信你真的是重写的方法和你没有意外改变了超类或子类的方法而不是两个,介绍了一个运行时错误,错误的实现的方法被称为造成不必要的行为。
#4
4
There's two key things that you should know.
有两件事你应该知道。
-
Overridden methods must have the exact signatures as their superclass have. (in your example this condition doesn't meet.)
重写方法必须具有与其超类相同的签名。(在你的例子中,这个条件没有满足。)
-
In Java for an object, we have two types: compile type and runtime type. In the following example compile type of
myobj
isObject
but its runtime type isCar
.在Java中,对象有两种类型:编译类型和运行时类型。在下面的例子中,myobj的编译类型是Object,但是它的运行时类型是Car。
public class Car{ @Override public boolean equals(Object o){ System.out.println("something"); return false; } }
Object myobj = new Car();
对象myobj =新车();
Also you should note that
myobj.equals(...)
results in printingsomething
in the console.您还应该注意myobject .equals(…)会导致在控制台中打印一些东西。
#1
112
The first thing you should note is that public boolean equals(Test testje)
doesn't override Object
's equals
, since the argument is Test
instead of Object
, so the signatures don't match.
首先要注意的是,公共布尔值(Test testje)不会覆盖对象的值,因为参数是Test而不是Object,所以签名不匹配。
Therefore the main
method calls equals(Test testje)
exactly once - when executing t3.equals(t3);
- since that's the only case in which both the static type of the instance equals
is executed for and the type of the argument are the Test
class.
因此,当执行t3.equals(t3)时,主方法调用等于(Test testje)一次;-因为这是唯一的一种情况,实例等于的静态类型和参数的类型都是测试类。
t3.equals(t3);
is the 4th equals
statement (which comes after 4 increments of the static count
variable), so 4 is printed.
t3.equals(t3);是第4个equals语句(在静态count变量的4个增量之后),因此输出4。
All the other equals
statements execute Object
's equals
, and therefore print nothing.
所有其他的等号语句执行对象的等号,因此不打印任何东西。
A more detailed explanation :
更详细的解释是:
t1.equals()
calls Object
's equals
regardless of the type of the argument, since the static (compile time) type of t1
is Object
, and the Test
class doesn't override that method. The Object
class doesn't have an equals
method with a single Test
argument, so equals(Test testje)
can't be called, regardless of the dynamic (runtime type) of t1
.
t1.equals()调用Object's equals,不管参数的类型如何,因为t1的静态(编译时)类型是Object,并且测试类不会覆盖该方法。对象类没有带有单个测试参数的equals方法,因此无论t1的动态(运行时类型)如何,都不能调用equals(Test testje)。
t3.equals()
can execute either Object
's equals
or Test
's equals, since the compile time type of t3
is Test
, and the Test
class has two equals
methods (one inherited from the Object
class and the other defined in the Test
class).
t3.equals()可以执行对象的equals或Test的equals,因为t3的编译时类型是Test,并且Test类有两个equals方法(一个继承自Object类,另一个定义在Test类中)。
The method being chosen depends on the compile time type of the argument : 1. When the argument is Object
(as in t3.equals(o1);
or t3.equals(t2);
), Object
's equals
is called and nothing is printed. 2. When the argument is Test
, as in t3.equals(t3);
, both versions of equals
match that argument, but due to the rules of method overloading, the method with the most specific argument - equals(Test testje)
- is chosen and the count
variable is printed.
所选择的方法取决于参数的编译时类型:1。当参数为Object(如t3.equals(o1));或t3.equals(t2);),对象的equals,并无打印。2。当参数被测试时,如t3.equals(t3)中;,两个版本的equals都匹配该参数,但是由于方法重载的规则,选择具有最特定参数的方法—equals(Test testje)—并打印count变量。
#2
11
The equals method in Test takes an instance of Test.
测试中的equals方法接受一个测试实例。
All the previous attempts have been made with an instance of Object, which take the inherrited method from the Object class:
之前所有的尝试都是通过对象实例进行的,对象实例采用对象类继承的方法:
public boolean equals(Object o){
return this == o;
}
Since there is no print in there, it won't print any value.
因为里面没有打印,所以不会打印任何值。
Your ++count;
will increment the value of count, so the moment when you actually call your
你的+ +计数;会增加计数的值,所以当你真正调用你的
public boolean equals(Test testje){...
method, that does print that value, the value of count is 4.
方法,它会打印那个值,count的值是4。
#3
7
t3.equals(t3)
is the only line which has the right arguments that match the method signature public boolean equals (Test testje)
so it's the only line in the program which actually calls that print statement. This question is designed to teach you a few things.
t3.equals(t3)是唯一的一行,它具有与方法签名公共布尔等于(Test testje)匹配的正确参数,因此它是程序中唯一调用打印语句的行。这个问题的目的是教你一些东西。
- All class implicitly extend Object
- 所有类都隐式地扩展对象
- Object.java contains an equals method which takes type Object
- 对象。java包含一个获取类型对象的equals方法
- multiple methods with the same name can exist provided they have different arguments - this is known as method overloading
- 只要有不同的参数,就可以存在具有相同名称的多个方法——这就是所谓的方法重载
- the method method overload who's signature matches the arguments at runtime is the method that gets invoked.
- 在运行时签名匹配参数的方法重载是被调用的方法。
Essentially the trick here is that Test implicitly extends Object like all java classes do. Object contains an equals method that takes type Object. t1 and t2 are typed such that at run time the arguments never match the method signature of equals that is defined in Test. Instead it's always calling into the equals method in Object.java because either the base type Is Object in which case the only methods you have access to are the ones defined in Object.java or the derived type is Object in which case
本质上,这里的诀窍是测试隐式地扩展对象,就像所有java类所做的那样。对象包含一个获取类型对象的equals方法。t1和t2的类型是这样的:在运行时,参数永远不会与测试中定义的方法签名相等。相反,它总是调用对象中的equals方法。因为要么基类型是对象,在这种情况下,您只能访问对象中定义的方法。在这种情况下,java或派生类型是Object
public boolean equals(Test testje)
Cannot be entered because in that case at runtime the argument is of type Object which is a Superclass of Test, not a subclass. So instead it looks at the equals method in the Test.java's implicitly typed superclass Object.java which also contains an equals method, which just happens to have a method signature of
不能输入,因为在运行时,参数是类型对象,它是测试的超类,而不是子类。相反,它会在测试中查看equals方法。java的隐式类型化的超类对象。java也包含一个equals方法,它刚好有一个方法签名
public boolean equals (Object o)
which in this case match our arguments at runtime so this equals method is the one that executes.
在这种情况下,它与我们在运行时的参数相匹配所以这个等于方法就是执行的那个。
Notice in the case of t3.equals(t3)
both the base type and the derived type of t3 are Test.
注意,在t3.equals(t3)的情况下,t3的基类型和派生类型都是Test。
Test t3 = new Test ();
this means that at runtime you are calling the equals method in Test.java and the argument you are passing in is actually of type Test so the method signatures match and the code inside Test.java executes. At this point count == 4
.
这意味着在运行时,您正在测试中调用equals方法。java和您传入的参数实际上是类型测试,所以方法签名匹配和测试中的代码。java执行。此时count == 4。
Bonus bit of knowledge for you:
给你一点额外的知识:
@Override
annotation you may have seen in a few places explicitly instructs the compiler to fail if it does not find method with the exact same signature somewhere in a Superclass. This is useful to know if you definitely intend to override a method and you want to be absolutely sure that you really are overriding the method and you haven't accidentally changed the method in either the superclass or subclass but not both and Introduced a runtime error where the wrong implementation of the method is being called causing unwanted behavior.
如果编译器在超类的某个地方找不到具有相同签名的方法,那么您可能在一些地方看到注释明确地指示编译器失败。这肯定有助于知道你打算覆盖一个方法,你要绝对相信你真的是重写的方法和你没有意外改变了超类或子类的方法而不是两个,介绍了一个运行时错误,错误的实现的方法被称为造成不必要的行为。
#4
4
There's two key things that you should know.
有两件事你应该知道。
-
Overridden methods must have the exact signatures as their superclass have. (in your example this condition doesn't meet.)
重写方法必须具有与其超类相同的签名。(在你的例子中,这个条件没有满足。)
-
In Java for an object, we have two types: compile type and runtime type. In the following example compile type of
myobj
isObject
but its runtime type isCar
.在Java中,对象有两种类型:编译类型和运行时类型。在下面的例子中,myobj的编译类型是Object,但是它的运行时类型是Car。
public class Car{ @Override public boolean equals(Object o){ System.out.println("something"); return false; } }
Object myobj = new Car();
对象myobj =新车();
Also you should note that
myobj.equals(...)
results in printingsomething
in the console.您还应该注意myobject .equals(…)会导致在控制台中打印一些东西。