Java 没有类型转换的编译器如何在子类中调用正确的 equals() 函数?

How is Java compiler without type casting calling a correct equals() function in subclass?

我有 ScheduledSessionViewModel class 扩展 AbstractSessionViewModel。这两个函数都实现了 equals() 函数。

class AbstractSessionViewModel {
   @Override public boolean equals(Object o) {
      return /* some logic */
   }
}

class ScheduledSessionViewModel extends AbstractSessionViewModel {
   @Override public boolean equals(Object o) {
      if (!super.equals(o)) return false;

      return /* some logic */;
   }
}

因为我使用的是新的 Android ListAdapter 我正在实施 DiffUtil.ItemCallback<T> 并且我有下一个方法:

@Override public boolean areContentsTheSame(AbstractSessionViewModel oldItem, AbstractSessionViewModel newItem) {
   if (oldItem instanceof ScheduledSessionViewModel && !(newItem instanceof ScheduledSessionViewModel)){
     return false;
   } else if (!(oldItem instanceof ScheduledSessionViewModel) && newItem instanceof ScheduledSessionViewModel){
     return false;
   } else if (oldItem instanceof ScheduledSessionViewModel){
     return ((ScheduledSessionViewModel)oldItem).equals((ScheduledSessionViewModel)newItem);
   } else {
     return oldItem.equals(newItem);
   }
}

奇怪的是,编译器在下一条语句中向我显示警告

((ScheduledSessionViewModel)oldItem).equals((ScheduledSessionViewModel)newItem);

不需要类型转换

这怎么可能? Java 编译器如何检测到 oldItemScheduledSessionViewModel 类型?

How's Java compiler able to detect that oldItem is of type ScheduledSessionViewModel?

不,不是;编译器只知道 oldItemAbstractSessionViewModel.

类型

不过没关系。编译器知道 AbstractSessionViewModelequals(Object) 方法,所以 actual 对象类型也有它。通过这种方式,编译器保证 equals(Object) 方法在运行时可用。

它是如何实现的 只有在运行时才知道。运行时根据 JLS 定义的一组规则搜索适当的方法。

旁注:经过上述说明后,我得出的结论是,通过正确实施 equals() 方法,下面是一个方法

@Override public boolean areContentsTheSame(AbstractSessionViewModel oldItem, AbstractSessionViewModel newItem) {
  if (oldItem instanceof ScheduledSessionViewModel && !(newItem instanceof ScheduledSessionViewModel)){
    return false;
  } else if (!(oldItem instanceof ScheduledSessionViewModel) && newItem instanceof ScheduledSessionViewModel){
    return false;
  } else if (oldItem instanceof ScheduledSessionViewModel){
    return ((ScheduledSessionViewModel)oldItem).equals((ScheduledSessionViewModel)newItem);
  } else {
    return oldItem.equals(newItem);
  }
}  

可以重构并且 if 语句是不必要的。 equals() 方法的实现应该处理所有事情。

最终结果:

@Override public boolean areContentsTheSame(AbstractSessionViewModel oldItem, AbstractSessionViewModel newItem) {
    return oldItem.equals(newItem);
}