子类继承私人领域?

这是一个面试问题。

子类是否继承私人领域?

我回答“否”,因为我们无法使用“正常OOP方式”访问它们。 但面试官认为他们是被遗传的,因为我们可以间接地访问这些领域或使用反思,他们仍然存在于对象中。

回来之后,我在javadoc中找到了下面的引用:

私人会员超级

子类不会继承其父类的私有成员。

你知道面试官的意见吗?

这里的问题/答案中的大部分困惑围绕着继承的定义。

显然,@DigitalRoss解释了一个子类的对象必须包含它的父类的私有字段。 正如他所说,没有私人成员并不意味着不在那里。

然而。 这与一个类的继承概念是不同的。 就像Java世界中存在语义问题的情况一样,仲裁器是Java语言规范 (当前是第3版)。

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

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

这解决了面试官提出的确切问题:“子继承私人领域”。 (强调加我)

答案是否定的,他们不。 子类的对象包含其超类的私有字段。 子类本身没有任何超类的私有字段。

这是一种学究性的语义吗? 是。 这是一个有用的面试问题吗? 可能不会。 但是JLS建立了Java世界的定义,而且这样做(在这种情况下)是毫不含糊的。

EDITED(删除了Bjarne Stroustrup的一个平行引用,由于java和c ++之间的差异,可能只会增加混淆,我会让我的答案停留在JLS 🙂

认识到有两个阶级,只有一个对象是很重要的。

所以,是的,当然它继承了私人领域。 它们大概是正确的对象功能所必需的,虽然父类的对象不是派生类的对象,但派生类的实例绝大部分肯定是父类的一个实例。 如果没有所有的领域,那就不太好了。

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

这是一个很好的问题!


更新:

错误,“不”

好吧,我想我们都学到了一些东西。 由于JLS起源于确切的“没有继承”的措辞,所以回答“否”是正确的。 由于子类不能访问或修改私有字段,换句话说,它们不被继承。 但是实际上只有一个对象,它确实包含了私有字段,所以如果有人以错误的方式使用JLS和教程的话,理解OOP,Java对象和实际发生的事情将是相当困难的。

更新以更新:

这里的争议涉及到一个基本的模糊性: 究竟究竟在讨论什么? 对象? 或者我们在某种意义上是在谈论班级本身? 当描述类而不是对象时,许多纬度是允许的。 所以子类不会继承私有字段,但作为子类实例的对象肯定包含私有字段。

不。私人领域不是继承…这就是为什么保护是发明。 这是设计。 我想这证明了保护修饰符的存在。


现在来到上下文。 你是什​​么意思继承 – 如果它在从派生类创建的对象中有? 是的。

如果你的意思是派生类可以是有用的。 那么,不。

现在,当你进行函数式编程时,超类的私有字段不会被有意义地继承给子类 。 对于子类,超类的私有字段与其他类的私有字段相同。

在功能上,它不是继承的。 理想情况是这样。


好吧,刚刚看了一下Java教程,他们引用了这个:

私人会员超级

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

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

我同意,该领域是在那里。 但是,子类没有得到任何私人领域的特权。 对于一个子类,私有字段与任何其他类的私有字段相同。

我相信这纯粹是一个观点问题。 你可以在任何一方塑造论点。 两种方式都更好。

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

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

考虑包转储中的两个类。 孩子延伸父母。

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

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

父 –

 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 

孩子 –

 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 

不,他们不会继承。

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

例如:

 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? } } 

您也可以通过反射来获取UseItcount 。 这并不意味着,你继承它。

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是隐藏的,并且被子类继承。 不过,正如DigitalRoss所指出的那样,价值在那里,而不是靠继承。

这样说吧。 如果你的父亲很富有,给你一张信用卡,你仍然可以用他的钱买东西,但并不意味着你继承了所有这些钱,是吗?

其他更新

这是非常有趣的, 要知道为什么属性在那里。

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

我们实际上可以改变父母和子类将仍然工作。

例如 :

 //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 

我想在这里可以找到确切的术语: JavaTM虚拟机规范

那么,我对面试官问题的回答是: 私人成员不是在子类中继承的,而是只能通过公共的getter或setter方法或任何原始类的适当的方法来访问子类或子类的对象。 通常的做法是保持成员私密,并使用公开的getter和setter方法访问它们。 那么当它们处理的私有成员不能被对象使用时,只继承getter和setter方法有什么意义呢? 这里的“继承”仅仅意味着它可以直接在子类中被子类中的新引入的方法所利用。

将下面的文件保存为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方法。 然后将DigitalClock作为Clock的子类。 在这里,如果DigitalClock的对象不包含小时和分钟的成员,那么事情就搞砸了。

看起来子类继承私有领域,因为这些领域被用在子类的内部工作中(从哲学上讲)。 一个子类在其构造函数中调用超类的构造函数。 如果超类的构造函数已经在构造函数中初始化了这些字段,超类私有字段显然会被调用超类构造函数的子类继承。 这只是一个例子。 但是当然没有accessor方法,子类不能访问父类的私有字段(就像不能够弹出iPhone的后面板来取出电池来重置手机…但电池仍然在那里)。

PS我遇到过很多继承定义之一:“继承 – 一种编程技术,它允许派生类扩展基类的功能,继承它的所有状态(强调是我的)和行为。

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

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

 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”的私有成员。 请让我知道你们的想法。

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

我们可以直接从他们的子类访问超类的私人领域吗?

然后答案是否定的 ,如果我们通过访问说明符的细节 ,提到私人成员只能在类本身访问。

但是,如果问题是

我们可以从他们的子类访问超类的私人领域吗?

这意味着什么,你会做什么访问私人会员并不重要。 在这种情况下,我们可以在超级市场上公开办法,你可以访问私人会员。 所以,在这种情况下,你正在创建一个接口/桥接来访问私有成员。

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

我认为私人领域不是继承,因为子类不能直接访问它。 或者换一种说法,我认为只是继承的方法 (包括访问私有领域),而不是领域。

我们可以简单地声明,当超类继承时,超类的私有成员实际上就是子类的私有成员,不能继承或不能继承子类的对象。

我将不得不回答在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”,所以人们认为它不是继承的。 但是,类中的每个非静态事物,无论是字段还是方法,都是被继承的。

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

Java中的内存布局相对于继承

在这里输入图像描述

不考虑填充位/对齐和VTABLE中包含的对象类。 所以这个子类的对象确实有一个超类的私有成员的地方。 但是,它不能从子类的对象中访问…

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

私人成员(国家和行为)是继承的。 它们(可以)影响由该类实例化的对象的行为和大小。 更不用说,它们通过所有可用的破坏破坏机制,或者可以由其实施者承担的子类很好地可见。

虽然继承有一个“事实上”的定义,但它肯定与“可见性”方面没有联系,而“可见性”方面则由“不”答案来承担。

所以,不需要外交。 JLS在这一点上是错误的。

任何不被“继承”的假设都是不安全和危险的。

因此,在两个事实上(部分)相互矛盾的定义(我不再重复)中,唯一应该遵循的是更安全(或安全)的定义。

Interesting Posts