首页 文章

子类是否继承私有字段?

提问于
浏览
217

这是一个面试问题 .

子类是否继承私有字段?

我回答“否”,因为我们无法使用“正常的OOP方式”访问它们 . 但是访谈者认为它们是继承的,因为我们可以间接地或使用反射来访问这些字段,它们仍然存在于对象中 .

我回来后,在javadoc找到了以下引用:

超类中的私有成员子类不继承其父类的私有成员 .

你知道面试官的意见吗?

17 回答

  • 213

    私有类成员或构造函数只能在顶级类(§7.6)的主体内访问,该类包含成员或构造函数的声明 . 它不是由子类继承的 . https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

  • 11

    子类不继承其父类的私有成员 . 但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法 .

  • 1

    私有成员(州和行为)是继承的 . 它们(可以)影响由类实例化的对象的行为和大小 . 更不用说它们通过所有可用的封装破坏机制对子类非常清晰可见,或者可以由它们的实现者承担 .

    虽然继承具有“事实”定义,但它绝对没有“可见性”方面的链接,这些方面由“否”答案假设 .

    所以,没有必要外交 . JLS在这一点上是错的 .

    任何他们不是“继承”的假设都是不安全和危险的 .

    因此,在两个事实上(部分)冲突的定义中(我将不再重复),唯一应该遵循的是更安全(或安全)的定义 .

  • 9

    问题/答案中的大部分混淆都围绕着继承的定义 .

    显然,正如@DigitalRoss所解释的那样,一个子类的 OBJECT 必须包含它的超类's private fields. As he states, having no access to a private member doesn' t意味着它不在那里 .

    然而 . 这与类的继承概念不同 . 正如java世界中存在语义问题的情况一样,仲裁器是Java Language Specification(目前是第3版) .

    正如JLS所述(https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2):

    声明为private的类的成员不会被该类的子类继承 . 只有声明为protected或public的类的成员才会被声明在声明类之外的包中声明的子类继承 .

    这解决了采访者提出的确切问题:“做sub CLASSES 继承私人领域” . (重点补充一下)

    答案是否定的 . 他们没有 . 子类的OBJECTS包含其超类的私有字段 . 子类本身没有其超类的私有字段的NO OFTION .

    这是一种迂腐的语义吗?是 . 这是一个有用的面试问题吗?可能不是 . 但是JLS Build 了Java世界的定义,并且它(在这种情况下)明确地这样做了 .

    EDITED(删除了Bjarne Stroustrup的并行引用,因为java和c之间的差异可能只会增加混乱 . 我会让我的答案依赖于JLS :)

  • 3

    是的

    重要的是要意识到虽然有两个类,但只有一个对象 .

    所以,是的,当然它继承了私有领域 . 它们可能是正确的对象功能必不可少的,虽然父类的对象不是派生类的对象,但派生类的实例绝大多数是父类的实例 . 如果没有所有的领域,那就不可能 .

    不,你不能直接访问它们 . 是的,它们是遗传的 . 他们必须是 .

    这是一个很好的问题!


    Update:

    错误,“不”

    好吧,我想我们都学到了一些东西 . 由于JLS起源于确切的"not inherited"措辞,因此回答"no"是正确的 . 由于子类无法访问或修改私有字段,因此,换句话说,它们不会被继承 . 但实际上只有一个对象,它确实包含私有字段,因此如果有人以错误的方式使用JLS和教程措辞,那么理解OOP,Java对象以及真正发生的事情将非常困难 .

    Update to update:

    这里的争议涉及一个基本的模糊性:究竟在讨论什么?物体?或者我们在某种意义上谈论 class 本身?在描述类而不是对象时,允许很多纬度 . 所以子类不继承私有字段,而是一个对象,它是子类的实例 certainly does contain the private fields.

  • 0

    不会 . 私有字段不会被继承......这就是为什么发明了Protected的原因 . 这是设计的 . 我想这证明了保护修饰符的存在 .


    现在来到这里 . 你继承的意思是什么 - 如果在派生类创建的对象中存在它?是的 .

    如果你的意思是它对派生类有用 . 好吧,不 .

    现在,当您进行函数式编程时,超类的私有字段不会以有意义的方式为子类继承 . 对于子类,超类的私有字段与任何其他类的私有字段相同 .

    从功能上讲,它不是遗传的 . 但 ideally ,确实如此 .


    好的,只是查看Java教程,他们引用了这个:

    超类中的私有成员子类不继承其父类的私有成员 . 但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法 .

    参考:http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html

    我同意,那个领域就在那里 . 但是,子类在该私有字段上没有任何特权 . 对于子类,私有字段与任何其他类的任何私有字段相同 .

    我相信's purely matter of point-of-view. You may mould the argument either side. It'两种方式都更合理 .

  • 1

    这取决于你对“继承”的定义 . 子类是否仍有内存中的字段?当然 . 可以直接访问它们吗?不,这只是定义的微妙之处;关键是要了解真正发生的事情 .

  • 0

    我必须回答Java中的私有字段是继承的 . 请允许我证明:

    public class Foo {
    
        private int x; // This is the private field.
    
        public Foo() {
            x = 0; // Sets int x to 0.
        }
    
        //The following methods are declared "final" so that they can't be overridden.
        public final void update() { x++; } // Increments x by 1.
        public final int getX() { return x; } // Returns the x value.
    
    }
    
    
    public class Bar extends Foo {
    
        public Bar() {
    
            super(); // Because this extends a class with a constructor, it is required to run before anything else.
    
            update(); //Runs the inherited update() method twice
            update();
            System.out.println(getX()); // Prints the inherited "x" int.
    
        }
    
    }
    

    如果您在程序 Bar bar = new Bar(); 中运行,那么您将始终在输出框中看到数字"2" . 因为整数"x"用方法 update()getX() 封装,所以可以证明整数是继承的 .

    令人困惑的是,因为你不能直接访问整数“x”,所以人们认为它不是继承的 . 但是,类中的每个非静态事物(无论是字段还是方法)都是继承的 .

  • -2

    我将用代码演示这个概念 . 子类ACTUALLY继承超类的私有变量 . 唯一的问题是除非为超类中的私有变量提供公共getter和setter,否则子对象无法访问它们 .

    考虑转发包中的两个类 . 孩子延伸父母 .

    如果我没记错的话,内存中的子对象由两个区域组成 . 一个是父部分,另一个是子部分 . 子级只能通过父级中的公共方法访问其父级代码中的私有区域 .

    这样想吧 . 波拉特的父亲博尔托克有一个10万美元的保险箱 . 他不想分享他的“私人”变量安全 . 所以,他没有为保险箱提供钥匙 . 波拉特继承了保险箱 . 但是,如果他甚至不能打开它会有什么好处呢?如果只有他的父亲提供了钥匙 .

    Parent -

    package Dump;
    
    public class Parent {
    
        private String reallyHidden;
        private String notReallyHidden;
    
        public String getNotReallyHidden() {
            return notReallyHidden;
        }
    
        public void setNotReallyHidden(String notReallyHidden) {
            this.notReallyHidden = notReallyHidden;
        }
    
    }//Parent
    

    Child -

    package Dump;
    
    public class Child extends Parent {
    
        private String childOnly;
    
        public String getChildOnly() {
            return childOnly;
        }
    
        public void setChildOnly(String childOnly) {
            this.childOnly = childOnly;
        }
    
        public static void main(String [] args){
    
            System.out.println("Testing...");
            Child c1 = new Child();
            c1.setChildOnly("childOnly");
            c1.setNotReallyHidden("notReallyHidden");
    
            //Attempting to access parent's reallyHidden
                c1.reallyHidden;//Does not even compile
    
        }//main
    
    }//Child
    
  • 70

    不,他们没有继承它 .

    其他一些类可能间接使用它的事实没有说继承,而是关于封装 .

    例如:

    class Some { 
       private int count; 
       public void increment() { 
          count++;
       }
       public String toString() { 
           return Integer.toString( count );
       }
    }
    
    class UseIt { 
        void useIt() { 
            Some s = new Some();
            s.increment();
            s.increment();
            s.increment();
            int v = Integer.parseInt( s.toString() );
            // hey, can you say you inherit it?
         }
    }
    

    您还可以通过反射在 UseIt 中获取 count 的值 . 这并不意味着,你继承它 .

    UPDATE

    即使值存在,它也不会被子类继承 .

    例如,子类定义为:

    class SomeOther extends Some { 
        private int count = 1000;
        @Override
        public void increment() { 
            super.increment();
            count *= 10000;
        }
    }
    
    class UseIt { 
        public static void main( String ... args ) { 
            s = new SomeOther();
            s.increment();
            s.increment();
            s.increment();
            v = Integer.parseInt( s.toString() );
            // what is the value of v?           
         }
    }
    

    这与第一个示例的情况完全相同 . 属性 count 被隐藏, not 完全由子类继承 . 尽管如此,正如DigitalRoss所指出的那样, Value 在那里,但不是通过继承手段 .

    这样说吧 . 如果你的父亲很有钱并且给你一张信用卡,你仍然可以用他的钱买东西,但这并不意味着你有这么多钱,是吗?

    Other update

    虽然很有意思,to know why the attribute is there.

    坦率地说,我没有确切的术语来描述它,但它是JVM及其工作方式,也加载了“未继承”的父定义 .

    我们实际上可以更改父级,子类仍然可以工作 .

    For instance

    //A.java
    class A {
       private int i;
       public String toString() { return ""+ i; }
    }
    // B.java
    class B extends A {}
    // Main.java
    class Main {
       public static void main( String [] args ) {
          System.out.println( new B().toString() );
        }
    }
    // Compile all the files
    javac A.java B.java Main.java
    // Run Main
    java Main
    // Outout is 0 as expected as B is using the A 'toString' definition
    0
    
    // Change A.java
    class A {
       public String toString() {
          return "Nothing here";
       }
    }
    // Recompile ONLY A.java
    javac A.java
    java Main
    // B wasn't modified and yet it shows a different behaviour, this is not due to 
    // inheritance but the way Java loads the class
    Output: Nothing here
    

    我猜这个确切的术语可以在这里找到:The JavaTM Virtual Machine Specification

  • 4

    那么,我对面试官问题的回答是 - Private members are not inherited in sub-classes but they are accessible to subclass or subclass's object only via public getter or setter methods or any such appropriate methods of original class. 通常的做法是保持成员私密并使用公开的getter和setter方法访问它们 . 那么,当他们处理的私有成员对对象不可用时,只继承getter和setter方法的重点是什么?这里'inherited'只是意味着它可以直接在子类中通过子类中新引入的方法来玩 .

    将以下文件保存为ParentClass.java并自己尝试 - >

    public class ParentClass {
      private int x;
    
      public int getX() {
        return x;
      }
    
      public void setX(int x) {
        this.x = x;
      }
    }
    
    class SubClass extends ParentClass {
      private int y;
    
      public int getY() {
        return y;
      }
    
      public void setY(int y) {
        this.y = y;
      }
    
      public void setXofParent(int x) {
        setX(x); 
      }
    }
    
    class Main {
      public static void main(String[] args) {
        SubClass s = new SubClass();
        s.setX(10);
        s.setY(12);
        System.out.println("X is :"+s.getX());
        System.out.println("Y is :"+s.getY());
        s.setXofParent(13);
        System.out.println("Now X is :"+s.getX());
      }
    }
    
    Output:
    X is :10
    Y is :12
    Now X is :13
    

    如果我们尝试在SubClass的方法中使用ParentClass的私有变量x,那么它不能直接访问任何修改(意味着没有继承) . 但是可以通过setXofParent()方法中的原始类的setX()方法在SubClass中修改x,或者可以使用setX()方法或最终调用setX()的setXofParent()方法使用ChildClass对象修改x . 所以这里setX()和getX()是ParentClass的私有成员x的一种门 .

    另一个简单的例子是Clock超类将小时和分钟作为私有成员,并将适当的getter和setter方法作为public . 然后DigitalClock作为Clock的子类 . 如果DigitalClock的对象不包含小时和分钟成员,那么事情就搞砸了 .

  • 0

    好吧,这是一个非常有趣的问题,我研究了很多,并得出结论,超类的私有成员确实可用(但不可访问)子类的对象 . 为了证明这一点,这里有一个带有父类和子类的示例代码,我正在将子类对象写入txt文件并在文件中读取名为'bhavesh'的私有成员,因此证明它确实可用于子文件class,但由于访问修饰符而无法访问 .

    import java.io.Serializable;
    public class ParentClass implements Serializable {
    public ParentClass() {
    
    }
    
    public int a=32131,b,c;
    
    private int bhavesh=5555,rr,weq,refw;
    }
    

    import java.io.*;
    import java.io.Serializable;
    public class ChildClass extends ParentClass{
    public ChildClass() {
    super();
    }
    
    public static void main(String[] args) {
    ChildClass childObj = new ChildClass();
    ObjectOutputStream oos;
    try {
            oos = new ObjectOutputStream(new FileOutputStream("C:\\MyData1.txt"));
            oos.writeObject(childObj); //Writing child class object and not parent class object
            System.out.println("Writing complete !");
        } catch (IOException e) {
        }
    
    
    }
    }
    

    打开MyData1.txt并搜索名为'bhavesh'的私有成员 . 请让我知道你们的想法 .

  • 0

    似乎子类确实继承了私有字段,因为这些字段在子类的内部工作中被用(哲学上讲) . 子类在其构造函数中调用超类构造函数 . 如果超类构造函数在其构造函数中初始化了这些字段,那么超类私有字段显然是由调用超类构造函数的子类继承的 . 这只是一个例子 . 但是当然没有访问器方法,子类无法访问超类私有字段(就像无法弹出iPhone的后面板以取出电池来重置手机......但电池仍在那里) .

    PS我遇到的许多继承定义之一:“继承 - 一种编程技术,它允许派生类扩展基类的功能,继承其所有的STATE(强调是我的)和行为 . ”

    私有字段,即使子类不可访问,也是超类的继承状态 .

  • 6

    Memory Layout in Java vis-a-vis inheritance

    enter image description here

    填充位/对齐以及在VTABLE中包含对象类是不考虑 . 因此,子类的对象确实为Super类的私有成员提供了一个位置 . 但是,无法从子类的对象访问它...

  • -1

    No ,私有字段不是继承的 . 唯一的原因是子类无法访问它们 directly .

  • 18

    我相信,答案完全取决于被问到的问题 . 我的意思是,如果问题是

    我们可以从他们的子类直接访问超类的私有字段吗?

    然后回答是 No ,如果我们通过access specifier details,就会提到,私有成员只能在类本身内访问 .

    但是,如果问题是

    我们可以从他们的子类访问超类的私有字段吗?

    这意味着,无关紧要,您将如何访问私有成员 . 在这种情况下,我们可以在超类中创建公共方法,您可以访问私有成员 . 因此,在这种情况下,您将创建一个接口/桥接来访问私有成员 .

    其他OOP语言如C,具有 friend function 概念,通过它我们可以访问其他类的私有成员 .

  • 9

    我们可以简单地声明,当继承超类时,超类的私有成员实际上成为子类的私有成员,并且不能进一步继承或无法使用子类的对象 .

相关问题