前言

最近开发过程中,遇到子类与父类使用同名字段的情形(具体业务就不多赘述),顺便就查了一下 Java 对此情形的处理。

先说结论:在 Java 中,当子类与父类有相同名称的字段时,它们不会相互影响

解释

字段(成员变量)在 Java 中是静态绑定的,这意味着字段的访问是在编译时决定的,而不是在运行时。

  • 独立存储:父类和子类的同名字段会视为不同的变量,它们在内存中是分开存储的。因此当修改子类的字段时,父类中的同名字段不会受到影响,反之亦然。
  • 字段遮蔽(Shadowing):当子类定义了与父类相同名称的字段时,子类的字段会遮蔽父类的字段。 在子类中直接访问字段时,访问到的将是子类自己的字段,而不是父类的字段。但父类的方法仍然会访问父类自己的字段。
  • 字段的访问:无论是在子类还是父类中,字段的访问总是基于声明的类型,而不是运行时的对象类型。也就是说,如果通过一个子类对象调用父类的方法,该方法仍然会使用父类的字段,而不会使用子类中的同名字段。

验证

以下字段以 protected 修饰 (public 同理)。

父类:

java
Parent.java
1
2
3
4
5
6
7
public class Parent {
    protected String field = "Parent field";

    public void printField() {
        System.out.println("Field in Parent: " + field);
    }
}

子类:

java
Child.java
1
2
3
4
5
6
7
public class Child extends Parent {
    protected String field = "Child field";

    public void printFieldInChild() {
        System.out.println("Field in Child: " + field);
    }
}

测试:

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class SameNameFieldTest {
    public static void main(String[] args) {
        Child child = new Child();

        // 调用父类的方法,会访问父类的字段
        child.printField();  // 输出 "Field in Parent: Parent field"

        // 调用子类的方法,会访问子类的字段
        child.printFieldInChild();  // 输出 "Field in Child: Child field"

        // 直接访问子类字段
        System.out.println("Direct access in Child: " + child.field);  // 输出 "Child field"

        // 强制类型转换为父类,并直接访问父类字段
        Parent parentReference = child;
        System.out.println("Direct access in Parent: " + parentReference.field);  // 输出 "Parent field"
    }
}

总结

当子类与父类有相同名称的字段时,它们不会相互影响。

若想在子类中访问父类的同名字段,可以使用 super.field 的形式获取。