使用公共getter从子类访问时,超级私有字段在哪里生存?

时间:2018-03-26 21:19:42

标签: java

不作为重复说明此问题地址该字段在该程序所在的地址不是它是否继承,或者是否继承但不可访问。

请继续阅读以了解

在下面的示例中,我们看到狗对象可以访问动物私有字段" name"抛弃使用公共getter" getName"但不是私有字段不是继承的,所以字段名称是生活

从搜索中我意识到只有一个对象是从子类创建的,而不是两个一个到sub,一个到super来保存私有字段。

立即关注>>我们都知道,任何一个班级的公共二传手都可以设置其私人领域,但我们知道这个领域的生活地点!在班级的对象

所以我的摘要问题如下:

所访问的私有字段位于子类创建的对象中!

它在哪里!

public class Animal {
    private String name ;
    public Animal (String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return this.name;
    }
}

public class Dog extends Animal {

    public Dog(String name) {
        super(name);
    }
}

public class Hello {
    public static void main(String[] args) {
        Dog mmms = new Dog("mmkk");
        System.out.println(mmms.getName());
    }
}

编辑:我认为这个问题可以说是

如果父类的私有字段未被继承,那么它的私有字段在哪里?

问题名称已更改,以便从

中获得更多理解

子类对象如何从公共getter访问其超类的私有成员?

使用公共getter从子类访问时,超级私有字段在哪里生存?

2 个答案:

答案 0 :(得分:1)

每当创建子类的实例时,在这种情况下就是Dog的实例,所有父类的构造函数都在一个序列中调用,以分配存储完整链状态所需的空间。在你的情况下,超级构造函数被显式调用,但即使没有显式调用,只要有一个默认构造函数(如果没有,那么代码不会编译),就会进行隐式调用。

有关父实例状态状态的信息可用,并与子实例一起存储。存储此信息的方式取决于Oracle JRE与OpenJRE不同的JVM实现。但是,无关紧要的是,孩子可能无法访问父项的字段或方法(在私有字段或方法的情况下),但所有字段都存在并分配了一个值,至少是默认值。所有方法也都存在,并根据vtable

进行调度

将实例方法分派给与定义类对应的实例部分。因此,如果在您的情况下,类Animal定义getNamesetName没有父路由到Dog重新定义它们,则JRE将执行维护状态的代码通过与Animal对应的部分,从而设置或检索存储在那里的name。同时,所有Java方法(包括私有)都是虚拟的,因此可以在子类中重写。有关此类覆盖的信息将保留在负责调度的vtable中。因此,如果您的班级Dog重新定义getNamesetName以执行其他操作(它将无法从该类定义访问字段name),那么请调用Dog实例上的方法实际上会调用Dog而不是Animal中定义的方法。在这种情况下,您可能会失去对name中字段Animal的任何访问权限(除非在Animal中定义了其他getter / setter),即使您在构造函数中放置了该值将保留存储。

如其他地方所示,人们仍然可以通过反射或字节码操作访问私人信息,但这很少或者由于非常特殊的原因(例如,私有字段上的@Inject注释可能导致设置)通过一些注入框架的价值)。即使可以这样做,通过反射访问私有隐藏(私有,受保护,包可见)方法或字段应该是一个例外而不是通常的做法,因为它显然违反了原始的设计决策。

进一步阅读:

答案 1 :(得分:0)

Dog只有一个实例也包含name实例变量,因为Dog Animal,尽管事实如此该字段未从它在实例中存在的父类中正确继承。

令您感到不安的是name无法直接从Dog代码访问,但它存在。它只是为了保护封装。

但是,您可以使用动态的公共或受保护方法来读取或修改此值,如getName()所示,或者您可以使用reflection来实现此目标:

Dog dog= new Dog("mmmk");
Field name = Animal.class.getDeclaredField("name");
name.setAccessible(true);
name.set(dog, "xxxxx");
System.err.println(dog.getName());

现在您可以看到name的值已被修改为“xxxxx”