Вы наблюдаете правильное поведение, но чтобы объяснить, почему, нам нужно обратиться к Java Спецификации языка.
§15.8.2. Литералы класса говорят
Тип C.class
, где C
- это имя класса, интерфейса или типа массива (§4.3), равно Class<C>
.
§ 4.3.2. Класс Object
говорит:
Тип выражения вызова метода getClass
: Class<? extends |T|>
, где T
- это класс или интерфейс, в которых был произведен поиск * 1023. * (§15.12.1) и |T|
обозначает стирание T
(§4.6).
§15.21.3. Операторы справочного равенства ==
и !=
говорят:
Ошибка времени компиляции, если невозможно преобразовать тип одного операнда в тип другого с помощью преобразование кастинга (§5.5). Значения времени выполнения двух операндов обязательно будут неравными (игнорируя случай, когда оба значения равны 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<? extends Doctor>
может быть удовлетворенным Class<Doctor>
или Class<Surgeon>
, но не Class<Employee>
, потому что Employee
не является подтипом Doctor
. Однако вы можете написать аналогичное выражение, которое даст ожидаемый результат, если вы передадите doctor
перед вызовом getClass
:
((Employee) doctor).getClass() == Employee.class
аналогичен случаю 2., так что это разрешено.
По общему признанию довольно необычно исправлять ошибку типа, используя upcast вместо downcasting.