Z次元
文章 笔记 日志
专题
专栏分类 文章归档
友链
友情链接 朋友圈
交流
留言 关于我
头像
系列文章
-
-
-
-
Java私有成员是否会被继承
系列文章
知识积累
最后更新:2024/12/15|创建时间:2021/12/12

文章讨论了Java中私有成员的继承问题,强调Java官方文档指出私有成员(属性和方法)不会被继承,但子类可以通过间接访问。通过实例分析,文章展示了子类对象实例化时调用父类构造器并初始化私有成员到内存中的过程,进而探讨了子类是否“真正”继承了父类的私有成员。最终得出结论:子类不直接继承私有成员,但可通过特定方式访问。

首先,Java官方文档中明确表示私有成员【即私有属性(field)和私有方法(method)】不会被继承。
图片

Only members of a class that are declared protected or public are inherited by subclasses declared in a package other than the one in which the class is declared.
Constructors, static initializers, and instance initializers are not members and therefore are not inherited.

图片

但是对于那句话,不同的人有不同的理解;
举个例子:

import org.openjdk.jol.info.ClassLayout;
import org.junit.Test;
import org.openjdk.jol.info.ClassLayout;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Apptext{
	@Test
    public void toTest(){
        ExtendPerson extendPerson = new ExtendPerson();
        System.out.println(ClassLayout.parseInstance(extendPerson).toPrintable());
    }
}
class Person {
    private String name ="ahzoo";
    public Person() {}
    public Person(String name){System.out.println(name);}
    private String getName() {return name;}
}
class ExtendPerson extends Person {
    public ExtendPerson() {}
}

ClassLayout需要引入依赖:

    <dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.8</version>
    </dependency>

图片
从上面的例子中可以看出,父类的私有成员在子类的内存中是出现了的

再举个例子:

 public class AppTest{
    @Test
    public void toTest2() throws Exception {
        ExtendPerson extendPerson = new ExtendPerson();
        extendPerson.doGet();
    }
}
class Person {
    private String name ="ahzoo";
    public Person() {}
    private String getName() {
        return name;
    }
    private void setName(String name) {
        this.name = name;
    }
    public void doGet(){
        System.out.println(getName()); //ahzoo
    }
}

class ExtendPerson extends Person {
    public ExtendPerson() {}
}

图片
从这个例子中可以看出,子类是可以获得父类的私有成员的
其它操作父类私有成员的方法:

public class AppTest{
     /**
     * 使用反射获取父类私有属性
     */
    @Test
    public void myTest() {

        Class clazz = ExtendPerson.class;
//        ExtendPerson person = (ExtendPerson) clazz.newInstance();
        List fieldsList = new ArrayList<Field>();
        // 获遍历所有父类
        for(; clazz != Object.class ; clazz = clazz.getSuperclass()) { 
            Field[] declaredFields = clazz.getDeclaredFields();
            // 保存得到的属性
            fieldsList.addAll(Arrays.asList(declaredFields));  
        }
    
        // 遍历获得的属性
        for (Object field : fieldsList) {  
            System.out.println(field); // private java.lang.String org.example.Person.name
        }
    }
    /**
     * 使用super获取操作父类私有成员
     */
	@Test
    public void toTest2() {
        ExtendPerson extendPerson = new ExtendPerson("ouo"); //将打印 ---ouo---
    }
}
class Person {
    private String name ="ahzoo";
    public Person() {}
    public Person(String name){System.out.println("---" + name + "---");}
    private String getName() {return name;}
    private void setName(String name) {this.name = name;}
    public void doGet(){System.out.println(getName());}
}

class ExtendPerson extends Person {
    public ExtendPerson() {}
    public ExtendPerson(String name) {super(name);}
}

总结下上面的例子:

  1. 子类的内存中出现了父类的属性
  2. 虽然子类不能直接操作父类属性,但是可以通过间接的方式操作(父类提供的公共方法、super方法或者反射)

以次可以推断出,子类确实是继承了父类的私有成员的。

但是我还是更偏向于Java官方文档的说法:

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

即:子类不会继承其父类的私有成员。但是,如果父类中具有能访问其私有字段的public或project修饰的方法,则子类也可以使用这些方法获取其私有成员。
图片

回顾下继承性:
子类继承父类时会在子类的构造器会在执行之前,使用super方法调用父类的构造器;
同理,在调用父类构造器时,父类构造器又会在执行之前调用子类父类的父类的构造器……以次造成连锁反应,直到调用到Object类的构造器为止;
每个类都会在其自身构造器执行之前完成父类构造器的执行,而构造器的作用就是获取其所在类的所有属性和方法,这其中自然也就包括了私有的。
对此,我的理解是:
子类对象在实例化时,调用到了父类的构造器,而父类构造器在执行时自然也就把其成员给初始化了,初始化到哪里了呢?自然是内存中,这也是为什么子类的内存中可以看到父类的私有成员;
但是由于封装性的原理,私有成员只能在自己的类中使用,所以子类是无法在自己的类中使用父类的私有成员的,既然无法使用,那我说他没有继承,也没什么问题吧;
这不就完美体现了继承性吗,所以再回到刚才那句Java官方文档对继承性就很合理了。

再举个通俗的例子:
儿子从父亲那里得到(继承)了很多东西,包括一栋房子,房子里有父亲的房间,由于父亲的房间属于私人空间,所以不能随意进入,需要从父亲那里拿到钥匙才能进入(钥匙就相当于父类的get方法),或者是父亲带你进去(super方法),亦或是找个开锁师傅(反射);那么儿子到底有没有继承这个房间呢?我的观点是没有。
图片

Java文档:
https://docs.oracle.com/javase/specs/index.html

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html
https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

版权声明
本文依据 CC-BY-NC-SA 4.0 许可协议授权,请您在转载时注明文章来源为 Z次元 ,若本文涉及转载第三方内容,请您一同注明。
更多专栏文章推荐
知识积累
人非生而知之者,孰能无惑?惑而不从师,其为惑也,终不解矣。
“类的成员”与“类的主体”
2021/12/11
将Jar包安装到本地Maven仓库
2021/12/9
JDK新版特性(18-21)
2025/2/7
JDK新版特性(11-17)
2025/1/30
评论区
发表评论

这里还没有评论哦

快来发一条评论抢占前排吧

目录
十玖八柒
每天进步多一点
欢迎到访φ(゜▽゜*)♪
最新评论
永恒末匕:

好哇塞,这个厉害

十玖八柒:

测试图片发送

Corwin: @十玖八柒

哎 主要是我的个人网站用的是静态的cos 实现评论框还是有点困难

十玖八柒: @Corwin

评论模块是自己写的,富文本编辑器是封装的Tiptap(这个编辑器非常强大,你可以去看下)

我的
个人主页
站点地图
RSS订阅
导航
十年之约
虫洞穿梭
全站友链
虚位以待
©2020 - 2025 By 十玖八柒 版权所有
豫ICP备20021466号