为何无自定义实例字段的子类,看似可使用父类私有实例字段?
我定义了一个包含两个私有实例字段(firstName、age)和一个公共实例字段(lastName)的Parent父类,以及一个无自定义实例字段的Student子类。但运行程序后,输出结果出现异常:父类实例的私有字段firstName输出结果前后矛盾,看起来像是被子类修改了。
代码实现
public class Parent { private String firstName; public String lastName; private int age; public Parent() { System.out.println("No-Parameter Constructor"); } public Parent(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public String toString() { return "firstName: " + firstName + " lastName: " + lastName + " age: " + age; } public String getFN() { return firstName; } } public class Student extends Parent { public Student(String firstName, String lastName, int age) { super(firstName, lastName, age); } public static void main(String[] args) { Parent p = new Parent("Logi", "Tech", 42); Student s = new Student("Logi", "Camera", 21); System.out.println(p); System.out.println(s); System.out.println(p); System.out.println(p.getFN()); } }
运行输出
firstName: Logi lastName: Tech age: 42 firstName: LogiStudent lastName: Camera age: 21 firstName: Logi lastName: Tech age: 42 LogiStudent
问题本质与解决方法
你看到的异常不是子类“拥有”了父类私有字段——Java的封装机制明确禁止子类直接访问父类私有字段,这是基本原则。你的输出异常大概率是由以下低级错误导致的:
字段被错误定义为静态:如果
Parent类的firstName被写成static字段,所有Parent和Student实例会共享这个字段。创建Student实例时会覆盖静态字段的值,导致getFN()返回修改后的值;如果toString方法里的firstName是硬编码或引用了其他变量,就会出现输出前后矛盾的情况。
解决:确保firstName是实例字段(去掉static修饰符)。局部变量覆盖实例字段:比如在
Parent的toString方法里,你定义了和实例字段同名的局部变量firstName,导致toString输出的是局部变量的固定值,而getFN()返回的是实例字段的实际修改后的值,造成输出矛盾。
解决:删除重复的局部变量,或者在实例字段前加this.明确引用(比如this.firstName)。构造方法错误拼接类名:如果
Parent构造方法里把this.firstName = firstName;写成了this.firstName = firstName + this.getClass().getSimpleName();,子类实例构造时会自动拼接类名,导致firstName变成"LogiStudent"。
解决:修正构造方法的赋值语句,确保只传入参数值。
另外,检查代码是否存在拼写错误(比如firstName和firstname大小写不一致),导致实际没有正确赋值实例字段,而是隐式创建了其他变量。
内容的提问来源于stack exchange,提问作者js07

