【问题标题】:inheritance private field in javajava中的继承私有字段
【发布时间】:2013-01-09 21:28:23
【问题描述】:

如果子类不能从超类继承私有成员,但它从超类继承了可以访问未继承的私有成员的公共方法,如此处所述

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

被继承的子类成员修改的超类私有成员存储在哪里?它们存在于哪里?

【问题讨论】:

    标签: java


    【解决方案1】:

    子类的实例包含其超类的所有成员,但是私有成员可能无法从子类中访问。

    【讨论】:

    • 如oracle教程中提到的子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。 link
    • 也许继承不是最好的词,但是子类的任何实例仍然包含超类的所有成员,只是不能直接访问。
    • @PaulBellora.. 私有成员不是子类的一部分。子类不继承它们。
    • @LeeMeador Nitpick:我会说“使用子类的实例” - 变量指向实例。
    • this argument about the semantics of inheritance 已经不是第一次发生了。
    【解决方案2】:

    将私有成员变量想象成存在于声明它们的类中。如果子类在其父类中调用更改成员变量的方法,请将该更改视为发生在父类中。这是在您的头脑中对其进行建模的有用方法,因为只有该父类才能拥有读取或写入该变量值的代码。

    子类必须向父类发出请求,然后对上面声明的成员变量做一些事情。

    如果您使用子类中的代码覆盖父类中的方法,则该覆盖方法无法访问私有成员变量,即使父类中的覆盖方法可以访问。子类中的覆盖方法可以调用父类中的覆盖方法。

    例如:

    public class Parent {
        private int bar = 0;
        public void setBar(int value) {
            bar = value;
        }
    }
    
    public class Derived extends Parent {
        @override
        public void setBar(int value) {
            bar = value + 1; // NOT ALLOWED
            super.setBar(value + 1); // ALLOWED (same result)
        }
    }
    

    低级信息:

    不过,在低层次上,我可能会创建一个 SubClass 的实例,它将为 SubClass 的所有实例变量和所有父类(包括 Object)分配一个内存块。

    方法本身的代码位于由某些 ClassLoader 为包含每个方法的类分配的一些内存中。这是按类别分配的。因此,即使数据一起存储在实例中,各种子类和父类的代码也不会存储在一起。

    访问规则只是不允许 SubClass 中的代码访问分配给父类或祖先类私有的实例变量的内存。

    但是,在这种情况下,很少值得花这么多精力去考虑它。这就是我的经验。其他人可能会有不同的看法。

    注意:有一些方法可以通过反射访问私有变量。

    可见性

    我可能需要一些帮助,因为我正在记忆中工作。

    为成员变量分配了四个可见性级别。这些与用于类变量和方法的四个相同。

    private - 这些变量只能被声明它们的同一类中的代码访问。 (嗯......它们也可以被该类中的内部类访问。)

    包 - 这些可以通过同一类中的代码和与该类相同的包中的任何类中的代码访问。具有该代码的类可能在您的源文件或某个 jar 文件中,或者实际上是在类路径中的任何位置。 (注意:没有关键字“包”。如果没有其他关键字表示可见性,则变量具有包级别的可见性。我喜欢将“包”这个词放在 /* */ 注释中。)

    受保护 - 可以通过同一类中的代码和该类的任何子类中的代码以及与该类相同包中的任何类中的代码来访问它们。

    public - 这些可以通过任何其他类中的代码访问。

    警告:在某些情况下,您原本期望可见的代码却没有。这是因为 ClassLoader(s) 的工作方式。 Java EE 有一个类加载器嵌套,您最终可能会导致一个类加载器加载的代码对另一个类加载器加载的代码不可见。您最终可以得到两个具有相同全名(包括包)的类。我认为所有这些都是“高级”主题,我必须阅读它来解释它。我确实想指出这种情况会发生,并且可能会让您怀疑可见性。

    public class MyClass {
        private int foo1 = 1;       // visible in this class only
        protected int foo2 = 2;     // visible here, in subclasses and in classes with same package
        int foo3 = 3;               // visible here and in classes with the same package
        public int foo4 = 4;        // visible here, there and everywhere
    
        /* package */ int foo5 = 5; // how I like to do 'package' variables with a comment
                                    //  to show I intended to do it on purpose. If you read
                                    //  my code you don't have to wonder if I forgot it.
    
        ...
    }
    

    最后一个实用说明:从长远来看,我发现将几乎所有成员变量设为私有非常有用。如果您需要将它们更改为更可见的内容,请这样做,或者可能只是创建具有所需可见性的 getter 和 setter 方法。一个优点是,如果我提供了一个 getter 而没有 setter,或者如果 getter 是公共的并且 setter 受到保护,我可以提供只读访问权限。我还可以创建一个可以设置但从不读取的只写变量。这适用于依赖注入,但您应该对此发表评论。也许你可以看到优势。缺点是您编写了更多代码行,但如果您愿意,其他 IDE 中的 eclipse 会为您生成这些方法。

    【讨论】:

    • 它很好地描述了引擎盖下发生的事情,但是如果该私有成员无法访问,您会说如果它“隐藏”,我的意思是如果子类存在于同一个超级包中-班级 ?相反,**不继承私有成员和隐藏私有成员有什么区别? **
    • @Lee Meador 我的意思是在前面的评论中,正如 oracle 教程中提到的......一个子类继承其父类的所有公共和受保护成员,无论子类是什么包in. 如果子类与其父类在同一个包中,它也继承父类的包私有成员
    • 不存在未继承的私有成员;它们总是隐藏的。
    • @Aladdin 我已经添加了关于可见性的答案。你所说的 package-private 就是我在答案本身中所说的 package 。它与 private 不同。
    • @Lee Meador 非常感谢,您解释了模棱两可的困惑,我已经不知不觉陷入了。
    猜你喜欢
    • 2020-10-25
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2018-09-19
    • 2011-09-26
    • 1970-01-01
    相关资源
    最近更新 更多