为什么这两种比较 Class 对象的结果不同?
Why do these two way to compare Class objects result differently?
我定义了两个类:Employee和Doctor,他们是父子。代码如下:
class Employee {
// ....
}
class Doctor extends Employee {
// ....
}
然后我写了一个像这样的主要方法:
public static void main(String[] args) {
Doctor doctor = new Doctor();
Employee employee = new Employee();
System.out.println(doctor.getClass() == new Employee().getClass()); // code 1
System.out.println(employee.getClass() == Employee.class); // code 2
System.out.println(doctor.getClass() == Employee.class); // code 3
}
但只有 code 1
和 code 2
是正确的,code 3
调用异常:
Error:(33, 46) Java: uncomparable type: java.lang.Class<capture#1 extends Doctor> and java.lang.Class<Employee>
而且我知道我可以使用equals
来处理这个问题,但我想知道为什么我不能使用运算符==
来比较它们。
您观察到的行为是正确的,但要解释原因,我们需要参考 Java 语言规范。
The type of C.class
, where C
is the name of a class, interface, or array type (§4.3), is Class<C>
.
The type of a method invocation expression of getClass
is Class<? extends |T|>
, where T
is the class or interface that was searched for getClass
(§15.12.1) and |T|
denotes the erasure of T
(§4.6).
§15.21.3. Reference Equality Operators ==
and !=
说:
It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values are null
).
所以,我们可以写下每个表达式的编译时类型:
Employee.class
属于 Class<Employee>
. 类型
Doctor.class
属于 Class<Doctor>
. 类型
employee.getClass()
和 new Employee().getClass()
都是 Class<? extends Employee>
类型。这意味着 Class
代表 Employee
或其子类,包括 Doctor
.
doctor.getClass()
和 new Doctor().getClass()
都是 Class<? extends Doctor>
类型。这意味着 Class
代表 Doctor
或其子类,例如Surgeon
也许。
现在我们可以解释所有三种行为:
doctor.getClass() == new Employee().getClass()
将 Class<? extends Doctor>
与 Class<? extends Employee>
进行比较。第一种类型可以通过强制转换转换为第二种类型,所以这是允许的。
employee.getClass() == Employee.class
将 Class<? extends Employee>
与 Class<Employee>
进行比较。第二种类型可以通过强制转换转换为第一种类型,所以这是允许的。
doctor.getClass() == Employee.class
将 Class<? extends Doctor>
与 Class<Employee>
进行比较。两种类型都不能通过强制转换转换为另一种类型,因此这是一个编译时错误(不是异常)。
关于 3. 的更多细节,Class<Doctor>
或 Class<Surgeon>
可以满足 Class<? extends Doctor>
,但 Class<Employee>
不能满足,因为 Employee
不是 Doctor
的子类型。但是,如果在调用 getClass
:
之前向上转换 doctor
,则可以编写一个类似的表达式,它具有预期的结果
((Employee) doctor).getClass() == Employee.class
与情况2类似,所以允许。
诚然,通过向上转型而不是向下转型来修复类型错误是很不寻常的。
我定义了两个类:Employee和Doctor,他们是父子。代码如下:
class Employee {
// ....
}
class Doctor extends Employee {
// ....
}
然后我写了一个像这样的主要方法:
public static void main(String[] args) {
Doctor doctor = new Doctor();
Employee employee = new Employee();
System.out.println(doctor.getClass() == new Employee().getClass()); // code 1
System.out.println(employee.getClass() == Employee.class); // code 2
System.out.println(doctor.getClass() == Employee.class); // code 3
}
但只有 code 1
和 code 2
是正确的,code 3
调用异常:
Error:(33, 46) Java: uncomparable type: java.lang.Class<capture#1 extends Doctor> and java.lang.Class<Employee>
而且我知道我可以使用equals
来处理这个问题,但我想知道为什么我不能使用运算符==
来比较它们。
您观察到的行为是正确的,但要解释原因,我们需要参考 Java 语言规范。
The type of
C.class
, whereC
is the name of a class, interface, or array type (§4.3), isClass<C>
.
The type of a method invocation expression of
getClass
isClass<? extends |T|>
, whereT
is the class or interface that was searched forgetClass
(§15.12.1) and|T|
denotes the erasure ofT
(§4.6).
§15.21.3. Reference Equality Operators ==
and !=
说:
It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values are
null
).
所以,我们可以写下每个表达式的编译时类型:
Employee.class
属于Class<Employee>
. 类型
Doctor.class
属于Class<Doctor>
. 类型
employee.getClass()
和new Employee().getClass()
都是Class<? extends Employee>
类型。这意味着Class
代表Employee
或其子类,包括Doctor
.doctor.getClass()
和new Doctor().getClass()
都是Class<? extends Doctor>
类型。这意味着Class
代表Doctor
或其子类,例如Surgeon
也许。
现在我们可以解释所有三种行为:
doctor.getClass() == new Employee().getClass()
将Class<? extends Doctor>
与Class<? extends Employee>
进行比较。第一种类型可以通过强制转换转换为第二种类型,所以这是允许的。employee.getClass() == Employee.class
将Class<? extends Employee>
与Class<Employee>
进行比较。第二种类型可以通过强制转换转换为第一种类型,所以这是允许的。doctor.getClass() == Employee.class
将Class<? extends Doctor>
与Class<Employee>
进行比较。两种类型都不能通过强制转换转换为另一种类型,因此这是一个编译时错误(不是异常)。
关于 3. 的更多细节,Class<Doctor>
或 Class<Surgeon>
可以满足 Class<? extends Doctor>
,但 Class<Employee>
不能满足,因为 Employee
不是 Doctor
的子类型。但是,如果在调用 getClass
:
doctor
,则可以编写一个类似的表达式,它具有预期的结果
((Employee) doctor).getClass() == Employee.class
与情况2类似,所以允许。
诚然,通过向上转型而不是向下转型来修复类型错误是很不寻常的。