成员变量访问看编译类型,方法调用看运行类型;字段同名是隐藏而非覆盖,方法同名是重写;要实现字段的多态效果,须通过重写的getter方法。

成员变量访问看编译类型
Java中成员变量不具有多态性,访问时完全由声明类型(即编译时类型)决定,和实际创建的对象类型无关。哪怕用子类对象赋值给父类引用,访问的仍是父类中定义的变量。
常见错误现象:Parent p = new Child(); System.out.println(p.value); 输出的是 Parent 类里的 value,即使 Child 也定义了同名 value 字段——这不是覆盖,而是隐藏(hiding),两者内存地址独立。
- 子类中声明同名成员变量不会覆盖父类变量,只是在子类实例中新增一个字段
- 通过父类引用无法直接访问子类新增的同名变量(编译报错)
- 若需访问子类变量,必须强制转型:
((Child)p).value
成员方法调用看运行类型
这才是多态的核心体现:方法调用在运行期根据实际对象类型动态绑定,只要方法是 virtual(非 static、非 private、非 final),就会走动态分派。
使用场景:父类定义通用接口,子类重写具体逻辑,如 Animal a = new Dog(); a.speak(); 真正执行的是 Dog.speak()。
华锐行业电子商务系统2.0采用微软最新的.net3.5(c#)+mssql架构,代码进行全面重整及优化,清除冗余及垃圾代码,运行速度更快、郊率更高。全站生成静态、会员二级域名、竞价排名、企业会员有多套模板可供选择;在界面方面采用DIV+CSS进行设计,实现程序和界面分离,方便修改适合自己的个性界面,在用户体验方面,大量使用ajax技术,更加易用。程序特点:一、采用微软最新.net3.5+MSSQL
立即学习“Java免费学习笔记(深入)”;
-
static方法属于类,调用看编译类型,不参与多态 -
private方法不能被继承,自然无法被重写,调用也只认编译类型 -
final方法可继承但不可重写,调用同样只按编译类型解析 - 构造方法不是普通成员方法,不参与多态,且隐式为
final
字段隐藏 vs 方法重写容易混淆的点
表面上都是“子类写同名东西”,但语义完全不同:字段是静态绑定+隐藏,方法是动态绑定+重写。这种不对称性是初学者最常踩的坑。
性能影响几乎为零,但逻辑错误风险高——尤其当误以为 p.field 和 p.method() 都会走到子类实现时,字段访问会静默返回父类值,难以调试。
- IDE通常不会对字段隐藏给出警告,但会对未重写父类抽象方法报错
- 字段访问无运行时开销;方法调用有虚方法表查找成本(现代JVM已高度优化,可忽略)
- 如果想让字段也“表现得像多态”,应封装为 getter 方法,再让子类重写该方法
class Parent {
String name = "Parent";
void show() { System.out.println("Parent.show"); }
String getName() { return name; }
}
class Child extends Parent {
String name = "Child"; // 隐藏,非覆盖
void show() { System.out.println("Child.show"); } // 重写
String getName() { return name; } // 重写 getter
}
public class Test {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.name); // 输出 "Parent"(看编译类型)
p.show(); // 输出 "Child.show"(看运行类型)
System.out.println(p.getName()); // 输出 "Child"(通过重写方法间接实现“多态字段”)
}
}
字段访问的静态性比很多人想象中更顽固——哪怕你把子类字段改成 public static,它依然不参与多态,只强化了“属于类而非对象”的属性。真正需要运行时行为的地方,别碰字段,用方法。









