1编译期选择
按引用声明类型 ParentChannel 查找字段 label,因此绑定 ParentChannel.label。
Inheritance Binding Lab
先组合一条合法赋值,再选择成员访问形式。实验台会把“编译期选择”与“运行期分派”拆开显示,避免把字段隐藏、静态隐藏和实例方法重写混成一条规则。
class ParentChannel {
String label = "父类字段";
static String kind() {
return "父类静态方法";
}
String message() {
return "父类实例方法";
}
}
class SmsChannel extends ParentChannel {
String label = "子类字段";
static String kind() {
return "子类静态方法";
}
@Override
String message() {
// 此处 super.message() 得到“父类实例方法”
return "子类实例方法";
}
}
“父类字段”
按引用声明类型 ParentChannel 查找字段 label,因此绑定 ParentChannel.label。
字段不参与动态分派;即使对象是 SmsChannel,也不会改查子类字段。
判定:字段访问由引用声明类型决定,字段隐藏不是方法重写。
如果同名方法存在多个参数列表,编译器先依据引用声明类型、实参的编译期类型选出方法签名,这一步是重载解析。签名确定后,若它是可重写实例方法,运行时才依据实际对象选择最终实现。
因此,“对象是子类”不会让编译器凭空看到只声明在子类中的重载版本。
message(Object),子类重写它,并另行重载 message(String)。ParentChannel 可见成员中选中 message(Object)。SmsChannel.message(Object);不会改选 message(String)。先判断,再看绑定阶段是否与你的理由一致。
1. ParentChannel ref = new SmsChannel(); 后,ref.label 会读取“子类字段”。
2. 同一赋值下,ref.message() 会在运行时调用 SmsChannel 的重写实现。
3. 重载与重写都只由运行时对象类型决定。