子类继承私有字段吗?

这是面试问题。

子类是否继承private 字段?< / p >

我的回答是“不”,因为我们不能使用“正常的面向对象的方式”访问它们。但是采访者认为它们是继承的,因为我们可以间接或使用反射访问这些字段,并且它们仍然存在于对象中。

回来后,我在javadoc中发现了以下引用:

超类中的私人成员

< p > 子类不继承私有

你知道面试官观点的论据吗?

260519 次浏览

这取决于你对“继承”的定义。子类在内存中仍然有字段吗?肯定。它能直接访问它们吗?不。这只是定义的微妙之处;关键是要理解到底发生了什么。

不。他们没有继承。

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

例如:

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的值。这并不意味着你继承了它。

更新

即使值在那里,它也不会被子类继承。

例如,一个子类定义为:

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

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

不。私有字段没有被继承…这就是受保护的被发明的原因。这是有意为之。我想这证明了受保护修饰符的存在。


现在来看看上下文。继承是什么意思——如果它存在于从派生类创建的对象中?是的,它是。

如果你的意思是它是否对派生类有用。嗯,没有。

现在,当你来到函数式编程父类的私有字段没有以一种有意义的方式继承给子类。对于子类,超类的私有字段与任何其他类的私有字段相同。

在功能上,它不是遗传的。但是理想情况下,它是。


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

超类中的私人成员

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

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

我同意,这个领域是存在的。但是,子类在私有字段上没有任何特权。对于子类,私有字段与任何其他类的私有字段相同。

我相信这只是个人观点的问题。你可以左右争论的任何一方。这两种方法都是合理的。

,

是的

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

当然,它继承了私有字段。它们大概是正确的对象功能所必需的,虽然父类的对象不是派生类的对象,但派生类的实例基本上肯定是父类的实例。如果没有所有的领域,就不可能是这样。

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

这是个好问题!


< em >更新:< / em >

呃,“不”

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

更新到更新:

这里的争议涉及到一个基本的模糊性:或者我们在某种意义上谈论课程本身?当描述类而不是对象时,允许有很大的自由度。因此,子类不继承私有字段,而是继承一个对象,该对象是子类当然包含私有字段。的实例

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

显然,正如@DigitalRoss解释的那样,子类的对象必须包含其父类的私有字段。正如他所说,无法访问私人会员并不意味着它不存在。

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

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

已声明类的成员 Private不被继承 该类的子类。只有成员 声明为受保护的类的 或public由子类继承 类以外的包中声明

这解决了面试官提出的确切问题:“sub是否继承私有字段”。(我强调了一下)

答案是否定的。他们没有。子类的对象包含父类的私有字段。子类本身没有父类的私有字段的概念。

这是学究性质的语义学吗?是的。这是个有用的面试问题吗?可能不会。但是JLS为Java世界建立了定义,并且这样做(在本例中)是明确的。

编辑(删除了Bjarne Stroustrup的平行引用,由于java和c++之间的差异,这可能只会增加混淆。我将让我的答案取决于JLS:)

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

< p > PS 我遇到的关于继承的许多定义之一是: “继承——一种编程技术,允许派生类扩展基类的功能,继承其所有的STATE(重点是我的)和行为。”< / p >

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

私有成员(状态和行为)是继承的。它们(可以)影响类实例化的对象的行为和大小。更不用说,通过所有可用的封装破坏机制,或者它们的实现者可以假定,子类可以很好地看到它们。

虽然继承有一个“事实上的”定义,但它肯定与“可见性”方面没有联系,这是“不”答案所假设的。

所以,没有必要采取外交手段。JLS在这一点上是错误的。

任何认为他们不是“遗传”的假设都是不安全的和危险的。

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

好吧,这是一个非常有趣的问题,我研究了很多,得出的结论是,父类的私有成员确实在子类的对象中可用(但不可访问)。为了证明这一点,这里是一个带有父类和子类的示例代码,我正在将子类对象写入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”的私有成员。请告诉我你们的想法。

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

直接可以访问超类的私有字段吗

然后答案是没有,如果我们通过访问说明符详细信息,它提到,私有成员只能在类本身中访问。

但是,如果问题是

是否可以访问超类的私有字段

这意味着,访问私有成员的操作并不重要。在这种情况下,我们可以在超类中创建public方法,你可以访问private成员。因此,在本例中,您创建了一个接口/桥接器来访问私有成员。

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

没有,私有字段不会被继承。唯一的原因是子类不能访问它们直接

我们可以简单地声明,当父类被继承时,父类的私有成员实际上成为子类的私有成员,并且不能被进一步继承或子类的对象不可访问。

好吧,我对面试官的问题的回答是——Private成员不会在子类中继承,但只能通过公共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

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

另一个简单的例子是Clock超类将hours和min作为私有成员,将适当的getter和setter方法作为公共方法。然后是数字时钟作为时钟的子类。在这里,如果DigitalClock的对象不包含hours和mins成员,那么事情就搞砸了。

我将用代码演示这个概念。子类实际上继承父类的私有变量。唯一的问题是它们不是可访问的到 子对象,除非您为私有变量提供公共getter和setter 在超级班。< / p >

考虑包转储中的两个类。子扩展父。

如果我没记错的话,内存中的子对象由两个区域组成。一个是父部分,另一个是子部分。子程序可以访问私有文件 节只能通过父类中的公共方法在其父类的代码中调用。< / p >

这样想。波拉特的父亲博尔托克有一个装有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

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

我必须回答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

Memory Layout in Java vis-a-vis inheritance .

enter image description here

填充位/对齐和VTABLE中对象类的包含不被考虑。因此,子类的对象确实为超类的私有成员留有一席之地。但是,它不能从子类的对象中访问…

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

< p >参考: https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html#:~:text=Private%20Members%20in%20a%20Superclass,be%20used%20by%20the%20subclass . < / p >

例如,

class Person {
private String name;


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


Person(String name) {
this.name = name;
}
}
public class Student extends Person {


Student(String name) {
super(name);
}
    

public String getStudentName() {
return this.getName(); // works
// "return this.name;" doesn't work, and the error is "The field Person.name is not visible"


}
}


public class Main {
public static void main(String[] args) {
Student s = new Student("Bill");


String name = s.getName(); // works
// "String name = s.name;" doesn't work, and the error is "The field Person.name is not visible"


System.out.println(name);
}
}
我可以试着帮你。
当一个子类(例如命名为B)扩展一个超类(例如命名为a)时,它自动从它的超类继承字段(例如属性和/或方法)。
现在,B在它的内存布局中为类A中的每一个字段预留了空间,即使是私有字段。事实上,Java不允许子类B使用私有字段,因为它们是私有的

正如其他人所指出的那样:

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2:

声明为private的类的成员不会被继承 该类的子类。只声明类的成员 Protected或public由包中声明的子类继承 除了声明类的那个

答案无疑是没有,没有任何if和but。这围绕着继承的定义。根据定义,继承是针对类的,不是针对对象的。对象是使用类定义创建的。继承只是添加到class定义中的另一个块。那么,类是否继承了父类的私有成员?没有