这是一个面试问题。
子类是否继承私有 字段?
我回答“否”,因为我们无法使用“普通OOP方式”访问它们。但是面试官认为他们是继承的,因为我们可以间接地或使用反射来访问这些领域,但它们仍然存在于对象中。
我回来后,在javadoc:
中找到了以下引文超类中的私人会员
一个 子类不继承私有 其父类的成员。
你知道面试官的意见吗?
答案 0 :(得分:222)
这里的问题/答案中的大多数混淆都围绕着继承的定义。
显然,正如@DigitalRoss所解释的,子类的 OBJECT 必须包含其超类的私有字段。正如他所说,无法访问私人会员并不意味着它不存在。
然而。这与类的继承概念不同。正如java世界中存在语义问题的情况一样,仲裁者是Java Language Specification(目前是第3版)。
正如JLS所述(https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2):
声明的类的成员 私人不是继承的 该类的子类。只有会员 声明受保护的类的 或public由子类继承 在除以外的包中声明 宣布上课的人。
这解决了访问者提出的确切问题:“做sub CLASSES 继承私有字段”。 (我强调)
答案是否定的。他们没有。子类的OBJECTS包含其超类的私有字段。子类本身没有其超类私有字段的NO OF。
这是一种迂腐的语义吗?是。这是一个有用的面试问题吗?可能不是。但是JLS建立了Java世界的定义,并且它(在这种情况下)明确地这样做。
EDITED(删除了Bjarne Stroustrup的并行引用,因为java和c ++之间的差异可能只会增加混乱。我会让我的答案依赖于JLS:)
答案 1 :(得分:71)
重要的是要意识到,当是两个类时,只有一个对象。
所以,是的,当然它继承了私有领域。它们可能是正确的对象功能必不可少的,虽然父类的对象不是派生类的对象,但派生类的实例绝对是父类的实例。如果没有所有的领域,那就不可能了。
不,您无法直接访问它们。是的,他们是继承的。他们有。
这是一个很好的问题!
<强> 更新 强>
嗯,我想我们都学到了一些东西。由于JLS产生了确切的“未继承”措辞,因此回答“no”是正确的。由于子类无法访问或修改私有字段,因此,换句话说,它们不会被继承。但实际上 只是一个对象,它真的确实包含私有字段,所以如果有人采用JLS和教程措辞错误的方式,理解OOP,Java对象以及真正发生的事情将非常困难。
更新更新:
这里的争议涉及一个基本的模糊性:究竟在讨论什么? 对象?或者我们在某种意义上谈论类本身?< / em>在描述类而不是对象时允许很多纬度。因此,子类不会继承私有字段,但是作为子类实例的对象肯定会包含私有字段。
答案 2 :(得分:18)
没有。私有字段不是继承的...这就是发明 Protected 的原因。这是设计的。我想这证明了保护修饰符的存在。
现在来到这里。你继承的意思是什么 - 如果在派生类创建的对象中存在?是的,它是。
如果你的意思是它对派生类有用。好吧,没有。
现在,当您进入函数式编程时,超类的私有字段不会以有意义的方式继承子类。对于子类,超类的私有字段与任何其他类的私有字段相同。
从功能上讲,它不是继承的。但理想情况,是。
好的,只需查看他们引用的Java教程:
超类中的私人会员
子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。
参考:http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html
我同意,这个领域就在那里。但是,子类在该私有字段上没有任何特权。对于子类,私有字段与任何其他类的任何私有字段相同。
我认为这纯粹是观点问题。你可以在任何一方塑造争论。这两种方式都更合理。
答案 3 :(得分:11)
这取决于你对“继承”的定义。子类是否仍有内存中的字段?当然。可以直接访问它们吗?不,这只是定义的微妙之处;关键是要了解到底发生了什么。
答案 4 :(得分:10)
我将用代码演示这个概念。子类ACTUALLY 继承超类的私有变量。唯一的问题是它们不能可访问 子对象,除非您为私有变量提供公共getter和setter 在超级班。
考虑Dump包中的两个类。孩子延伸父母。
如果我没记错的话,内存中的子对象由两个区域组成。一个是父部分,另一个是子部分。孩子可以进入私人 其父代码中的部分仅通过父代的公共方法。
这样想。波拉特的父亲博尔托克有一个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
答案 5 :(得分:9)
没有。他们不继承它。
其他一些类可能间接使用它的事实没有说继承,而是关于封装。
例如:
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?
}
}
您还可以通过反射在count
内获取UseIt
的值。这并不意味着,你继承了它。
更新
即使值存在,它也不会被子类继承。
例如,子类定义为:
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所指出的那样,价值在那里,但不是通过继承手段。
这样说吧。如果你的父亲很富有并且给你一张信用卡,你仍然可以用他的钱买东西,但这并不意味着你有 继承 所有这些钱,是吗?
其他更新
虽然很有意思,to know why the attribute is there.
我坦率地说没有确切的术语来描述它,但它是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
我想确切的术语可以在这里找到:The JavaTM Virtual Machine Specification
答案 6 :(得分:6)
嗯,我对面试官问题的回答是 - 私有成员不是在子类中继承的,但只能通过公共getter或setter方法或任何原始类的适当方法访问子类或子类的对象。< / strong>通常的做法是保持成员私有,并使用公共的getter和setter方法访问它们。那么,当他们处理的私有成员对对象不可用时,只继承getter和setter方法的重点是什么?这里'继承'只是意味着它可以直接在子类中使用,可以通过子类中新引入的方法来实现。
将以下文件保存为ParentClass.java并自行尝试 - &gt;
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的对象不包含小时和分钟成员,那么事情就搞砸了。
答案 7 :(得分:4)
好的,这是一个非常有趣的问题,我经常研究并得出结论,超类的私有成员确实可用(但不可访问)子类的对象。为了证明这一点,这里有一个带有父类和子类的示例代码,我正在将子类对象写入txt文件并读取名为&#39; bhavesh&#39;的私有成员。在文件中,因此证明它确实在子类中可用但由于访问修饰符而无法访问。
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并搜索名为&#39; bhavesh&#39;的私人成员。请让我知道你们的想法。
答案 8 :(得分:3)
似乎子类确实继承了私有字段,因为这些字段在子类的内部工作中被用(哲学上讲)。子类在其构造函数中调用超类构造函数。如果超类构造函数在其构造函数中初始化了这些字段,那么超类私有字段显然是由调用超类构造函数的子类继承的。这只是一个例子。但是当然没有访问器方法,子类无法访问超类私有字段(就像无法弹出iPhone的后面板以取出电池来重置手机......但电池仍在那里)。
PS 我遇到的许多继承定义之一: “继承 - 一种编程技术,允许派生类扩展基类的功能,继承其所有的STATE(强调是我的)和行为。”
私有字段,即使子类不可访问,也是超类的继承状态。
答案 9 :(得分:1)
例如,
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);
}
}
答案 10 :(得分:1)
否,不会继承私有字段。唯一的原因是子类无法直接访问 。
答案 11 :(得分:0)
我们可以简单地声明,当继承超类时,超类的私有成员实际上成为子类的私有成员,并且不能进一步继承或无法使用子类的对象。
答案 12 :(得分:0)
我相信,答案完全取决于被问到的问题。我的意思是,如果问题是
我们可以直接访问超类的私有字段 他们的子类?
然后回答否,如果我们通过access specifier details,则提到私有成员只能在班级内访问。
但是,如果问题是
我们可以从中访问超类的私有字段吗? 他们的子类?
这意味着,无关紧要,您将如何访问私有成员。在这种情况下,我们可以在超类中创建公共方法,您可以访问私有成员。因此,在这种情况下,您将创建一个接口/网桥来访问私有成员。
其他OOP语言(如C ++)具有 friend function
概念,我们可以通过该概念访问其他类的私有成员。
答案 13 :(得分: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”,那么人们认为它不是继承的。但是,类中的每个非静态事物,无论是字段还是方法,都是继承的。
答案 14 :(得分:0)
私有类成员或构造函数只能在包含成员或构造函数声明的顶级类(§7.6)的主体内访问。它不是由子类继承的。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6
答案 15 :(得分:0)
子类不继承其父类的私有成员。但是,如果超类具有用于访问其私有字段的公共或受保护的方法,则子类也可以使用这些方法
答案 16 :(得分:-1)
子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。
答案 17 :(得分:-2)
继承私有成员(状态和行为)。它们(可以)影响由类实例化的对象的行为和大小。更不用说它们通过可用的所有封装破坏机制对子类非常清晰可见,或者可以由其实施者承担。
虽然继承具有“defacto”定义,但它绝对没有“可见性”方面的链接,这些方面由“否”答案假设。
所以,没有必要外交。 JLS在这一点上是错的。
任何假设他们不是“继承”都是不安全和危险的。
因此,在两个事实上(部分)冲突的定义中(我不会重复),唯一应该遵循的是更安全(或安全)的定义。